Allow only one installer instance

From NSIS Wiki
Jump to navigationJump to search
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

See also