Archive: Need Help with Set and Release Mutex!


Need Help with Set and Release Mutex!
  Can someone please assist with the proper way to call the createmutex API? What I am trying to do is to set a mutex flag while I am installing an update so that if my application is executed anytime during the update process, the application will not start until the mutex is released. An example would be great on how to do set the flag and remove it. Thanks




!define PATCHEXE "MutexTest.exe"

Name "Mutex Test"

OutFile "MutexTest.exe"

SilentInstall silent


Section "MainSection"

System::Call 'kernel32::CreateMutex( s, b, s) i(.r0, FALSE, "{E27D1C1E-B4D8-4439-83B4-0173E03C5D11}") .r3'


SectionEnd ; end the section


1) You need to do is call this from .onInit so it will set the mutex when the installer starts and not when it starts installing.
2) You need to do is call CreateMutexA because there is no function called CreateMutex, only CreateMutexA for MBCS and CreateMutexW for Unicode.
3) You should specify t for strings and not s. Also, b is not a valid type, use i for int (same as BOOL).
4) lpMutexAttributes is a pointer and therefore should be defined as i and not s.
5) You need to call GetLastError after this call and compare it to ERROR_ALREADY_EXISTS (183) to know if the mutex already exists.

Your code should be (not tested, plesae test):

Function .onInit
System::Call 'kernel32::CreateMutexA(i, i, s) i(0, 0, "myMutex")'
System::Call 'kernel32::GetLastError() i() .r0'
StrCmp $0 183 0 +3
MessageBox MB_OK "installer already running"
Abort
StrCmp $0 0 done
MessageBox MB_OK "error creating mutex, getlasterror didn't return success"
done:
FunctionEnd

This still is not working properly, this is what I tried, it provided me with no errors and allowed multiple instances.

!define PATCHEXE "MutexTest.exe"

Name "Mutex Test"

OutFile "MutexTest.exe"

SilentInstall silent


Function .onInit
System::Call 'kernel32::CreateMutexA(i, i, s) i(0, 0, "myMutex")'
System::Call 'kernel32::GetLastError() i() .r0'
StrCmp $0 183 0 +3
MessageBox MB_OK "installer already running"
Abort
StrCmp $0 0 done
MessageBox MB_OK "error creating mutex, getlasterror didn't return success"
done:
MessageBox MB_OK "mutex set"
FunctionEnd

Section Test
SectionEnd


The problem is between GetLastError and the actual function call there are some other functions called... I'll talk to the creator of the plug-in about finding a solution for this, but in the mean while you can use this little plug-in I have just created (attached). Here's an example:

Function .onInit
Mutex::Create "myMutex"
Pop $0
StrCmp $0 0 done
StrCmp $0 1 0 error
MessageBox MB_OK|MB_ICONSTOP "Installer already running..."
Abort
error:
MessageBox MB_OK|MB_ICONSTOP "Error creating mutex (probably bad mutex name)"
done:
FunctionEnd

Thanks alot, the plugin worked wonderfully!!!!!. For anyone who has had the problem with updating files becouse they are in use or becouse the application was ran during your update, this is the best fix I have found. I would even reccomend that this be an option on the installer becouse it would help prevent install or update failures. Thanks again for the solution.


Ok, minor bug (with calling any proc(void)) fixed, and GetLastError() option added. Use "?e" at proc specification, and pop first value from stack as getlasterror result.

Here what you want (and update dll and sources please):

  System::Call 'kernel32::CreateMutexA(i 0, i 0, t "myMutex") i .r1 ?e'

pop $0
StrCmp$0 183 0 +3
MessageBox MB_OK "installer already running"
Abort
StrCmp$0 0 done
MessageBox MB_OK "error creating mutex, getlasterror didn't return success"
done:

Updated CVS, thanks.


what is "mutex" in detail?
i dont know about ther kernel routines and M$ ist not very useful to me.


Well, seems pretty clear to me:

A mutex object is a synchronization object whose state is set to signaled when it is not owned by any thread, and nonsignaled when it is owned. Only one thread at a time can own a mutex object, whose name comes from the fact that it is useful in coordinating mutually exclusive access to a shared resource. For example, to prevent two threads from writing to shared memory at the same time, each thread waits for ownership of a mutex object before executing the code that accesses the memory. After writing to the shared memory, the thread releases the mutex object.
Any more details you want to know?

huh?

is it possible to explain it with simple words to me?

What about "myMutex" - that's the object?


A mutex is a lock. It can be locked by one program so the other can't open it. In our case, your program creates a mutex and locks it. The installer tries to open this mutex, and if it sees that the mutex is locked it concludes that your program is running.

Every mutex has an unique name, in the example above it's "myMutex".


is a "mutex" an option from that program or is it automatically created?

on 1st it not sure that program is really running - or am i wrong?


Your program has to create a mutex using a function called CreateMutex.

I don't understand the second question, what is unsure and when?


That's very interesting Kichik...

Is it possible to find mutex names (if any) from all applications?
It could be useful if Quake2 (game) is still running when it musn't be..

-Stu


If the application has created a mutex it's possible. All you need to know is the name. Mutexes are global or at least global on the current session (in XP fast-switching or NT terminal services).

Mutexes also have security attributes, so the application can deny you from opening the mutex. But you'll still be able to know the application is there because the mutex exists :)


So, say if the exe or game is called quake2, then the mutex will probably be called quake2 right?
I'll look into this...

Thanks again btw

-Stu


No, that's not a sure thing. Wasn't Quake 2 originally a DOS game? It might not set a mutex at all. Open it using Dependency Walker and see if it calls CreateMutex (under kernel32.dll).


Originally posted by brainsucker
  System::Call 'kernel32::CreateMutexA(i 0, i 0, t "myMutex") i .r1 ?e'

pop $0
StrCmp$0 183 0 +3
MessageBox MB_OK "installer already running"
Abort
StrCmp$0 0 done
MessageBox MB_OK "error creating mutex, getlasterror didn't return success"
done:
do I need to destroy the Mutex I create in the .onInit Function or is that done automatically?

Vytautas

You can close it using ReleaseMutex / CloseHandle. However, it's not really required, because it will be released when the process has ended.


Originally posted by brainsucker
Ok, minor bug (with calling any proc(void)) fixed, and GetLastError() option added. Use "?e" at proc specification, and pop first value from stack as getlasterror result.
[/PHP]
can you explain what Use "?e" at proc specification means? when i used this code in my script it always went to the error leg. why can't i create the mutex successfully? sorry, i'm very ignorant when it comes to windows API.

Tried this code?

http://nsis.sourceforge.net/site/ind...&tx_faq_faq=29


?e tells System.dll to return the return value of GetLastError on the stack. It is only available in the latest CVS version, so unless you're using that System.dll will probably fail. Get it using NSIS Update or the nightly snapshot in the NSIS homepage.


Thanks! It worked after i copied the new System.dll.


It seems to me that one would want to use this technique in both .onInit and un.onInit. For example, one's module might control a shared component, and a user might unknowingly think it's okay to uninstall one app using that component while installing another.

But one can't actually use this technique for that purpose, because if you're doing an upgrade, you might have to run the uninstaller before placing the new files, which would mean 2 threads using the same mutex.

Is there a suggested way to handle this?


Have the uninstaller create the mutex only if a certain command-line switch was NOT present and have the upgrade installer launch the uninstaller with that switch, but the standard unsinstall shortcuts/entries should launch without the switch.

Vytautas


Do i need the plugins mentioned above on the v2 final ?


No, you only have to use the standard System plug-in.


thx


I'm trying to create a mutex and use the installer on windows 7.

My problem here is that windows 7 always reports that the installer is running, even at the first startup.

This is the code I use:

; Allow only one installer instance
System::Call 'kernel32::CreateMutexA(i 0, i 0, t "myMutex") i .r1 ?e'
Pop $R0
StrCmp $R0 0 +3
MessageBox MB_OK "Running"
Quit
Maybe there is something wrong with my code.

I would be pleased if someone is able to find out what the problem is here.

Thanks a lot!

I think it should be "CreateMutexA(i 0, i 0, t "myMutex") i .r0 ?e".
See: http://nsis.sourceforge.net/Allow_on...aller_instance


I don't think you should use GetLastError (?e) to determine the result of CreateMutex. Instead of i.r0 ?e on the end, just use i.s. The rest of the code can stay the same as CreateMutex will return 0 (NULL) on failure.

Stu


I think it should be "CreateMutexA(i 0, i 0, t "myMutex") i .r0 ?e".
See: http://nsis.sourceforge.net/Allow_on...aller_instance
This doesn't work for me either

I don't think you should use GetLastError (?e) to determine the result of CreateMutex. Instead of i.r0 ?e on the end, just use .s. The rest of the code can stay the same as CreateMutex will return 0 (NULL) on failure.
I used the following code to check out .s:
System::Call 'kernel32::CreateMutexA(i 0, i 0, t "myMutex") .s'
But this time the CreateMutex results in nothing - not even a number. I tested it with MessageBox MB_OK $R0

Edit: Ah! What I found out is that I'm using the UAC library and because of this the program seems to start twice at the first time - I printed out the message of the return value of createMutex and it appears twice! It may not relate to this topic.

I'm going to ask my question in the related plugin topic, so if someone of you got an answer please answer in that topic

Sorry I meant i.s not .s.

Stu