- NSIS Discussion
- Need Help with Set and Release Mutex!
Archive: Need Help with Set and Release Mutex!
billym
16th April 2003 18:38 UTC
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
kichik
16th April 2003 20:39 UTC
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
billym
16th April 2003 22:11 UTC
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
kichik
17th April 2003 11:41 UTC
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
billym
17th April 2003 15:29 UTC
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.
brainsucker
17th April 2003 21:20 UTC
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:
kichik
18th April 2003 12:20 UTC
Updated CVS, thanks.
Brummelchen
8th July 2003 13:36 UTC
what is "mutex" in detail?
i dont know about ther kernel routines and M$ ist not very useful to me.
kichik
8th July 2003 13:44 UTC
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?
Brummelchen
8th July 2003 14:31 UTC
huh?
is it possible to explain it with simple words to me?
What about "myMutex" - that's the object?
kichik
8th July 2003 14:41 UTC
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".
Brummelchen
8th July 2003 14:46 UTC
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?
kichik
8th July 2003 14:51 UTC
Your program has to create a mutex using a function called CreateMutex.
I don't understand the second question, what is unsure and when?
Afrow UK
8th July 2003 17:47 UTC
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
kichik
8th July 2003 17:51 UTC
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 :)
Afrow UK
8th July 2003 18:15 UTC
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
kichik
9th July 2003 12:21 UTC
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).
Vytautas
18th September 2003 05:40 UTC
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
Joost Verburg
18th September 2003 13:43 UTC
You can close it using ReleaseMutex / CloseHandle. However, it's not really required, because it will be released when the process has ended.
putty
14th November 2003 19:04 UTC
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.
Joost Verburg
14th November 2003 19:07 UTC
Tried this code?
http://nsis.sourceforge.net/site/ind...&tx_faq_faq=29
kichik
14th November 2003 19:08 UTC
?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.
putty
14th November 2003 20:55 UTC
Thanks! It worked after i copied the new System.dll.
dpbluegreen
12th July 2004 23:11 UTC
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?
Vytautas
12th July 2004 23:48 UTC
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
Brummelchen
13th July 2004 11:48 UTC
Do i need the plugins mentioned above on the v2 final ?
Joost Verburg
13th July 2004 13:06 UTC
No, you only have to use the standard System plug-in.
Brummelchen
13th July 2004 14:44 UTC
thx
klopfdreh
9th May 2011 07:17 UTC
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!
jpderuiter
9th May 2011 09:38 UTC
I think it should be "CreateMutexA(i 0, i 0, t "myMutex") i .r0 ?e".
See: http://nsis.sourceforge.net/Allow_on...aller_instance
Afrow UK
9th May 2011 17:13 UTC
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
klopfdreh
10th May 2011 07:11 UTC
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
Afrow UK
10th May 2011 11:13 UTC
Sorry I meant i.s not .s.
Stu