Archive: Help with ReleaseMutex


Help with ReleaseMutex
  Hi, I was wondering if anyone could advise me on how to go about using this API call.

BOOL WINAPI ReleaseMutex(
HANDLE hMutex
);


I have a macro, provided by the wiki pages:
!macro MutexCheck _mutexname _outvar
System::Call 'kernel32::CreateMutexA(i 0, i 0, t "${_mutexname}") i .${_outvar} ?e'
pop ${_outvar}
!macroend


Upon reading the "Synchronization Object Security and Access Rights" page on MSDN, I noticed this:
MUTEX_MODIFY_STATE (0x0001) Modify state access, which is required for the ReleaseMutex function.
I need to change my macro to include this? So that the installer can modify it?

I'm also not exactly sure how to get the Handle of the Mutex. I'm guessing it's not simply it's name right?

The reason I want to release the Mutex, is that my installer creates two mutex's. One identical to the game I'm trying to patch (so they cannot run the game while trying to patch), and one of it's own, so the user can't run it twice. (reason there being two is that I can set a specific message depending on what the situation is.)

Anyways. At the finish page, I have the option to lauch said game I'm patching. The game won't lauch if it loads faster than the installer can close itself (almost always). So I want to release the Mutex in my Finish Page preFunction.

Thank you very much for your time in reading this.

There is a plugin at wiki http://nsis.sourceforge.net/CreateMutex_plug-in that might be helpful.


Unfortunately that plug-in only deals with the creation of a mutex. Not releasing one.

Maybe I wasn't direct enough in my first post, I apologise.
What I am after is a basic example of how to use the ReleaseMutex API call using the System plug-in. And also if I need to modify the existing Macro to allow for permissions to release it.

Thank you for your assistance : )


You're welcome!
Just found this forum thread.
http://forums.winamp.com/showthread....hreadid=131968
I hope that should be helpful.


Ah, I also came across that thread during my search. While it seemed promising from the title, after the user found out how to create the Mutex, they didn't bother discussing anything further on how to release it. Hee hee~

I guess all the System/API guru's are on holiday at the moment? : (
Oh well, I might have to remove the 'run' tickbox at the end.

Thanks again for your reply.


The MSDN page for CreateMutex says the return value is the mutex handle. The macro you have is storing the handle (the return code) in _outvar, but then pops the System::Call return code from GetLastError into the same variable. I suggest changing the macro to put the handle into its own variable:


!macro MutexCheck _mutexname _outvar hMutex
System::Call 'kernel32::CreateMutexA(i 0, i 0, t "${_mutexname}") i .${_hMutex} ?e'
pop ${_outvar}
!macroend


And use it something like this:

!insertmacro MutexCheck "myMutex" $0 $1
intCmp $1 0 MutexError
...
System::Call 'kernel32::ReleaseMutexA(i $1) i.r0'
IntCmp $0 0 MutexError2


Don

Don't forget to use CloseHandle on the mutex when you are done with it - Windows won't destroy it until all processes that have an open handle on the mutex close it.

While it is true that Windows will clean up when the process exits, relying on this is really a sign of poor code; you should always clean up your own resources explicitly.

Duncan


Thank you all very much for your replies!

Here is what I have so far:
Macro:

!macro MutexCheck _mutexname _outvar _hMutex
System::Call 'kernel32::CreateMutexA(i 0, i 0, t "${_mutexname}") i .${_hMutex} ?e'
pop ${_outvar}
!macroend


Usage:
!insertmacro MutexCheck "${MyMutexName}" $0 $9
StrCpy $MutexHandle $9
StrCmp $0 0 launch
StrLen $0 "$(^Name)"
IntOp $0 $0 + 1
loop:
FindWindow $1 '#32770' '' 0 $1
IntCmp $1 0 +4
System::Call "user32::GetWindowText(i r1, t .r2, i r0) i."
StrCmp $2 "$(^Name)" 0 loop
System::Call "user32::SetForegroundWindow(i r1) i."
Abort
launch:


Release:
System::Call 'kernel32::ReleaseMutexA(i $MutexHandle) i.r0'
MessageBox MB_OK "Unlocked. Return: $0"


MessageBox is displaying "Return: error"
Hmm, when I use...

System::Call 'kernel32::CloseHandle(i $MutexHandle) i.r0'
MessageBox MB_OK "Unlocked. Return: $0"

It returns 0, but still doesn't lat me lauch.

Does the loop have something to do with it?

Your MutexCheck macro has syntax errors. i.$$0 is not a valid parameter definition for the System plug-in. You should pass i.r0 instead.


Thanks kichik for your reply.

I was wondering if you could explain a little further about my error.
Sorry to say, but I'm still pretty green on the System plug-in, API calls, and the using the internal NSIS stack itself.

I'm not sure how you are getting i.$$0
Is that from "i .${_hMutex}" ?

I've tried many other arrangements, and I'm still not able to get it working. I even stripped everything down to the very basics:

System::Call 'kernel32::CreateMutexA(i 0, i 0, t "${MyMutexName}") i.r0 ?e'

>Pop $0
StrCpy $MutexHandle$0
StrCmp$0 0 launch
MessageBox MB_OK "Mutant inuse"
Abort
launch:
>MessageBox MB_OK "Mutex open"
>System::Call 'kernel32::ReleaseMutexA(i $MutexHandle) i.r0'
>MessageBox MB_OK "Mutex released. Return: $0"
This is very puzzling for me, as I'm really not sure what's going on.
It is returning error. Is that because I'm using invalid parameter definition?
Or is it because I need to change the default security settings of the Mutext itself?

Thank you again for your time.

It was supposed to be just `i.$0`, I had a typo. System plug-in parameters are divided into three - type, input and output. When you use $0 for the output, the actual value of $0 will be copied into there and you'll eventually get something like `i.123`. This doesn't tell System where to put the value it gets, it tells it what value to put there. You must tell it in which register you want to put the value, and that can only be done with `r*`.

You also have another error there, where the type is wrong. It's a pointer to an integer, not an integer. Use an asterisk before the `i`.

For more information, read the System manual, it has a few step by step guides and some examples.


Thank you kichik.

I finally got it working : )

Here's a snippet if anyone else is having any issues with it:


"MutexNameHere"

>!macro MutexCheck _mutexname _outvar _handle
System
::Call 'kernel32::CreateMutexA(i 0, i 0, t "${_mutexname}" ) i.r1 ?e'
>StrCpy ${_handle} $1
Pop${_outvar}
!macroend

>Function .onInit
>!insertmacro MutexCheck "${MyMutexName}" $0 $9
StrCmp$0 0 launch
StrLen$0 "$(^Name)"
IntOp $0 $0 + 1
loop:
FindWindow $1 '#32770' '' 0 $1
StrCmp$1 0 +1 +2
IntOp$3 $3 + 1
IntCmp$3 3 +5
System::Call "user32::GetWindowText(i r1, t .r2, i r0) i."
StrCmp $2 "$(^Name)" 0 loop
System::Call "user32::SetForegroundWindow(i r1) i."
System::Call "user32::ShowWindow(i r1,i 9) i."
Abort
launch:
!insertmacro MutexCheck "GameMutexHere" $0 $MutexHandle
StrCmp$0 0 launchB
StrLen$0 "GameWindowNameHere"
IntOp $0 $0 + 1
loopB:
FindWindow $1 ***91;"ClassHere"***93; ***91;"GameWindowNameHere"***93; ""
IntCmp $1 0 +3
System::Call "user32::GetWindowText(i r1, t .r2, i r0) i."
StrCmp $2 "GameWindowNameHere" 0 loopB
MessageBox MB_OK|MB_ICONEXCLAMATION "Please close Game before continuing."
System::Call "user32::SetForegroundWindow(i r1) i."
System::Call "user32::ShowWindow(i r1,i 9) i."
Abort
launchB:
>FunctionEnd

>Function "PreFinishFunc" ;Finish Page 'pre_function'
>System::Call 'kernel32::CloseHandle(i $MutexHandle) i.'
>FunctionEnd
>
Also, for some strange reason, when using FindWindow, and the '#32770' class, it was returning *every* result before my installer. Even 'console', and '0' ?
So I had to put in a little counter of sorts, to let it find 0 once before skipping ahead to the abort.

As you can see, I'm not the neatest, or most innovative scripter about, so don't expect anything special : P

Thanks once again for everyone's help.

sorry, small question:
what do you need "ReleaseMutex" for? :)

i never used it, because every mutex my installers create on startup seem to be released automatically with their shutdown again.


Originally posted by Comm@nder21
sorry, small question:
what do you need "ReleaseMutex" for? :)

i never used it, because every mutex my installers create on startup seem to be released automatically with their shutdown again.
It's in the first post. :p

ah, read it!
sounds reasonable :)