Allow only one installer instance: Difference between revisions
From NSIS Wiki
Jump to navigationJump to search
No edit summary |
(Simplified mutex code and added file code) |
||
(50 intermediate revisions by 24 users not shown) | |||
Line 1: | Line 1: | ||
== | {{PageAuthor|Anders}} | ||
[[Category:System Plugin Examples]] | |||
== Mutex == | |||
A [http://docs.microsoft.com/en-us/windows/win32/sync/mutex-objects mutex] is perhaps the best way to detect if another instance is running: | |||
<highlight-nsis> | <highlight-nsis> | ||
System::Call ' | !define INSTALLERMUTEXNAME "$(^Name)" ; TODO: Should really use a GUID here! (guidgenerator.com or guidgen.com) | ||
!ifndef NSIS_PTR_SIZE & SYSTYPE_PTR | |||
!define SYSTYPE_PTR i ; NSIS v2.x | |||
!else | |||
!define /ifndef SYSTYPE_PTR p ; NSIS v3.0+ | |||
!endif | |||
!macro ActivateOtherInstance | |||
StrCpy $3 "" ; Start FindWindow with NULL | |||
loop: | |||
FindWindow $3 "#32770" "" "" $3 | |||
StrCmp 0 $3 windownotfound | |||
StrLen $0 "$(^UninstallCaption)" | |||
IntOp $0 $0 + 1 ; GetWindowText count includes \0 | |||
System::Call 'USER32::GetWindowText(${SYSTYPE_PTR}r3, t.r0, ir0)' | |||
StrCmp $0 "$(^UninstallCaption)" windowfound "" | |||
StrLen $0 "$(^SetupCaption)" | |||
IntOp $0 $0 + 1 ; GetWindowText count includes \0 | |||
System::Call 'USER32::GetWindowText(${SYSTYPE_PTR}r3, t.r0, ir0)' | |||
StrCmp $0 "$(^SetupCaption)" windowfound loop | |||
windowfound: | |||
SendMessage $3 0x112 0xF120 0 /TIMEOUT=2000 ; WM_SYSCOMMAND:SC_RESTORE to restore the window if it is minimized | |||
System::Call "USER32::SetForegroundWindow(${SYSTYPE_PTR}r3)" | |||
windownotfound: | |||
!macroend | |||
!macro SingleInstanceMutex | |||
!ifndef INSTALLERMUTEXNAME | |||
!error "Must define INSTALLERMUTEXNAME" | |||
!endif | |||
System::Call 'KERNEL32::CreateMutex(${SYSTYPE_PTR}0, i1, t"${INSTALLERMUTEXNAME}")?e' | |||
Pop $0 | |||
IntCmpU $0 183 "" launch launch ; ERROR_ALREADY_EXISTS? | |||
!insertmacro ActivateOtherInstance | |||
Abort | |||
launch: | |||
!macroend | |||
Function .onInit | |||
!insertmacro SingleInstanceMutex | |||
FunctionEnd | |||
Function un.onInit | |||
!insertmacro SingleInstanceMutex | |||
FunctionEnd | |||
</highlight-nsis> | </highlight-nsis> | ||
== | == File == | ||
A open file handle that denies shared access can be used to detect a existing instance: | |||
<highlight-nsis> | <highlight-nsis> | ||
#TODO !define INSTALLERLOCKFILEGUID "{....}" ; Use a GUID here! (guidgenerator.com or guidgen.com) | |||
!macro SingleInstanceFile | |||
!ifndef INSTALLERLOCKFILEGUID | |||
!error "Must define INSTALLERLOCKFILEGUID" | |||
!endif | |||
!if "${NSIS_PTR_SIZE}" > 4 | |||
!include util.nsh | |||
!else ifndef IntPtrCmp | |||
!define IntPtrCmp IntCmp | |||
!endif | |||
!ifndef NSIS_PTR_SIZE & SYSTYPE_PTR | |||
!define SYSTYPE_PTR i ; NSIS v2.x | |||
!else | |||
!define /ifndef SYSTYPE_PTR p ; NSIS v3.0+ | |||
!endif | |||
!if "${NSIS_CHAR_SIZE}" < 2 | |||
Push "$TEMP\${INSTALLERLOCKFILEGUID}.lock" | |||
!else | |||
Push "$APPDATA\${INSTALLERLOCKFILEGUID}.lock" | |||
!endif | |||
System::Call 'KERNEL32::CreateFile(ts,i0x40000000,i0,${SYSTYPE_PTR}0,i4,i0x04000000,${SYSTYPE_PTR}0)${SYSTYPE_PTR}.r0' | |||
${IntPtrCmp} $0 -1 "" launch launch | |||
MessageBox MB_ICONSTOP "Already running!" | |||
Abort | |||
launch: | |||
!macroend | |||
Function .onInit | |||
!insertmacro SingleInstanceFile | |||
FunctionEnd | |||
Function un.onInit | |||
!insertmacro SingleInstanceFile | |||
FunctionEnd | |||
</highlight-nsis> | </highlight-nsis> | ||
== See also == | |||
* [[CreateMutex plug-in]] | |||
* [[Check whether your application is running]] |
Latest revision as of 18:31, 4 September 2019
Author: Anders (talk, contrib) |
Mutex
A mutex is perhaps the best way to detect if another instance is running:
!define INSTALLERMUTEXNAME "$(^Name)" ; TODO: Should really use a GUID here! (guidgenerator.com or guidgen.com) !ifndef NSIS_PTR_SIZE & SYSTYPE_PTR !define SYSTYPE_PTR i ; NSIS v2.x !else !define /ifndef SYSTYPE_PTR p ; NSIS v3.0+ !endif !macro ActivateOtherInstance StrCpy $3 "" ; Start FindWindow with NULL loop: FindWindow $3 "#32770" "" "" $3 StrCmp 0 $3 windownotfound StrLen $0 "$(^UninstallCaption)" IntOp $0 $0 + 1 ; GetWindowText count includes \0 System::Call 'USER32::GetWindowText(${SYSTYPE_PTR}r3, t.r0, ir0)' StrCmp $0 "$(^UninstallCaption)" windowfound "" StrLen $0 "$(^SetupCaption)" IntOp $0 $0 + 1 ; GetWindowText count includes \0 System::Call 'USER32::GetWindowText(${SYSTYPE_PTR}r3, t.r0, ir0)' StrCmp $0 "$(^SetupCaption)" windowfound loop windowfound: SendMessage $3 0x112 0xF120 0 /TIMEOUT=2000 ; WM_SYSCOMMAND:SC_RESTORE to restore the window if it is minimized System::Call "USER32::SetForegroundWindow(${SYSTYPE_PTR}r3)" windownotfound: !macroend !macro SingleInstanceMutex !ifndef INSTALLERMUTEXNAME !error "Must define INSTALLERMUTEXNAME" !endif System::Call 'KERNEL32::CreateMutex(${SYSTYPE_PTR}0, i1, t"${INSTALLERMUTEXNAME}")?e' Pop $0 IntCmpU $0 183 "" launch launch ; ERROR_ALREADY_EXISTS? !insertmacro ActivateOtherInstance Abort launch: !macroend Function .onInit !insertmacro SingleInstanceMutex FunctionEnd Function un.onInit !insertmacro SingleInstanceMutex FunctionEnd
File
A open file handle that denies shared access can be used to detect a existing instance:
#TODO !define INSTALLERLOCKFILEGUID "{....}" ; Use a GUID here! (guidgenerator.com or guidgen.com) !macro SingleInstanceFile !ifndef INSTALLERLOCKFILEGUID !error "Must define INSTALLERLOCKFILEGUID" !endif !if "${NSIS_PTR_SIZE}" > 4 !include util.nsh !else ifndef IntPtrCmp !define IntPtrCmp IntCmp !endif !ifndef NSIS_PTR_SIZE & SYSTYPE_PTR !define SYSTYPE_PTR i ; NSIS v2.x !else !define /ifndef SYSTYPE_PTR p ; NSIS v3.0+ !endif !if "${NSIS_CHAR_SIZE}" < 2 Push "$TEMP\${INSTALLERLOCKFILEGUID}.lock" !else Push "$APPDATA\${INSTALLERLOCKFILEGUID}.lock" !endif System::Call 'KERNEL32::CreateFile(ts,i0x40000000,i0,${SYSTYPE_PTR}0,i4,i0x04000000,${SYSTYPE_PTR}0)${SYSTYPE_PTR}.r0' ${IntPtrCmp} $0 -1 "" launch launch MessageBox MB_ICONSTOP "Already running!" Abort launch: !macroend Function .onInit !insertmacro SingleInstanceFile FunctionEnd Function un.onInit !insertmacro SingleInstanceFile FunctionEnd