Skip to content

Commit ec3c15d

Browse files
committed
fix(nsis): NSIS installer "CHECK_APP_RUNNING" breaks if installer has same executable file name as app
Closes #894
1 parent 92ad554 commit ec3c15d

File tree

2 files changed

+172
-11
lines changed

2 files changed

+172
-11
lines changed

templates/nsis/allowOnlyOneInstallerInstance.nsh

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
!include "nsProcess.nsh"
2+
!include "getProcessInfo.nsh"
23

34
# http://nsis.sourceforge.net/Allow_only_one_installer_instance
45
!macro ALLOW_ONLY_ONE_INSTALLER_INSTANCE
@@ -23,15 +24,18 @@
2324
!macroend
2425

2526
!macro CHECK_APP_RUNNING MODE
26-
${nsProcess::FindProcess} "${APP_EXECUTABLE_FILENAME}" $R0
27-
${If} $R0 == 0
28-
MessageBox MB_OKCANCEL|MB_ICONEXCLAMATION "${PRODUCT_NAME} is running. $\r$\nClick OK to close it and continue with ${MODE}." /SD IDOK IDOK doStopProcess
29-
Quit
30-
doStopProcess:
31-
DetailPrint "Closing running ${PRODUCT_NAME} ..."
32-
${nsProcess::KillProcess} "${APP_EXECUTABLE_FILENAME}" $R0
33-
DetailPrint "Waiting for ${PRODUCT_NAME} to close."
34-
Sleep 2000
35-
${EndIf}
36-
${nsProcess::Unload}
27+
${GetProcessInfo} 0 $0 $1 $2 $3 $4
28+
${if} $3 != "${APP_EXECUTABLE_FILENAME}"
29+
${nsProcess::FindProcess} "${APP_EXECUTABLE_FILENAME}" $R0
30+
${If} $R0 == 0
31+
MessageBox MB_OKCANCEL|MB_ICONEXCLAMATION "${PRODUCT_NAME} is running. $\r$\nClick OK to close it and continue with ${MODE}." /SD IDOK IDOK doStopProcess
32+
Quit
33+
doStopProcess:
34+
DetailPrint "Closing running ${PRODUCT_NAME} ..."
35+
${nsProcess::KillProcess} "${APP_EXECUTABLE_FILENAME}" $R0
36+
DetailPrint "Waiting for ${PRODUCT_NAME} to close."
37+
Sleep 2000
38+
${EndIf}
39+
${nsProcess::Unload}
40+
${endIf}
3741
!macroend

templates/nsis/getProcessInfo.nsh

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
; NSIS PROCESS INFO LIBRARY - GetProcessInfo.nsh
2+
; Version 1.1 - Mar 28th, 2011
3+
;
4+
; Description:
5+
; Gets process information.
6+
;
7+
; Usage example:
8+
; ${GetProcessInfo} 0 $0 $1 $2 $3 $4
9+
; DetailPrint "pid=$0 parent_pid=$1 priority=$2 process_name=$3 exe=$4"
10+
;
11+
; History:
12+
; 1.1 - 28/03/2011 - Added uninstall function, include guards, file header. Fixed getting full exe path on pre vista systems. (Sergius)
13+
;
14+
15+
!ifndef GETPROCESSINFO_INCLUDED
16+
!define GETPROCESSINFO_INCLUDED
17+
18+
!define PROCESSINFO.TH32CS_SNAPPROCESS 2
19+
!define PROCESSINFO.INVALID_HANDLE_VALUE -1
20+
21+
!define GetProcessInfo '!insertmacro GetProcessInfo'
22+
23+
;@in pid_in - if 0 - get current process info
24+
;@out pid_out - real process id (may be useful, if pid_in=0)
25+
;@out ppid - parent process id
26+
;@out priority
27+
;@out name - name of process
28+
;@out fullname - fully-qualified path of process
29+
!macro GetProcessInfo pid_in pid_out ppid priority name fullname
30+
Push ${pid_in}
31+
!ifdef BUILD_UNINSTALLER
32+
Call un._GetProcessInfo
33+
!else
34+
Call _GetProcessInfo
35+
!endif
36+
;name;pri;ppid;fname;pid;
37+
Pop ${name}
38+
Pop ${priority}
39+
Pop ${ppid}
40+
Pop ${fullname}
41+
Pop ${pid_out}
42+
!macroend
43+
44+
!macro FUNC_GETPROCESSINFO
45+
Exch $R3 ;pid
46+
Push $0
47+
Push $1
48+
Push $2
49+
Push $3
50+
Push $4
51+
Push $5
52+
Push $R0 ;hSnapshot
53+
Push $R1 ;result
54+
Push $R9 ;PROCESSENTRY32;MODULEENTRY32 and so on
55+
Push $R8
56+
57+
;zero registers to waste trash, if error occurred
58+
StrCpy $0 ""
59+
StrCpy $1 ""
60+
StrCpy $2 ""
61+
StrCpy $3 ""
62+
StrCpy $4 ""
63+
StrCpy $5 ""
64+
65+
IntCmp $R3 0 0 skip_pid_detection skip_pid_detection
66+
System::Call 'kernel32::GetCurrentProcess() i.R0'
67+
System::Call "Kernel32::GetProcessId(i R0) i.R3"
68+
69+
skip_pid_detection:
70+
System::Call 'Kernel32::CreateToolhelp32Snapshot(i ${PROCESSINFO.TH32CS_SNAPPROCESS},i R3) i.R0'
71+
72+
IntCmp $R0 ${PROCESSINFO.INVALID_HANDLE_VALUE} end ;someting wrong
73+
74+
;$R9=PROCESSENTRY32
75+
;typedef struct tagPROCESSENTRY32 {
76+
; DWORD dwSize;
77+
; DWORD cntUsage;
78+
; DWORD th32ProcessID;
79+
; ULONG_PTR th32DefaultHeapID;
80+
; DWORD th32ModuleID;
81+
; DWORD cntThreads;
82+
; DWORD th32ParentProcessID;
83+
; LONG pcPriClassBase;
84+
; DWORD dwFlags;
85+
; TCHAR szExeFile[MAX_PATH];
86+
;}PROCESSENTRY32, *PPROCESSENTRY32;
87+
;dwSize=4*9+2*260
88+
89+
System::Alloc 1024
90+
pop $R9
91+
System::Call "*$R9(i 556)"
92+
93+
System::Call 'Kernel32::Process32FirstW(i R0, i $R9) i.R1'
94+
StrCmp $R1 0 end
95+
96+
nnext_iteration:
97+
System::Call "*$R9(i,i,i.R1)" ;get PID
98+
IntCmp $R1 $R3 exitloop
99+
100+
System::Call 'Kernel32::Process32NextW(i R0, i $R9) i.R1'
101+
IntCmp $R1 0 0 nnext_iteration nnext_iteration
102+
103+
exitloop:
104+
;$0 - pid
105+
;$1 - threads
106+
;$2 - ppid
107+
;$3 - priority
108+
;$4 - process name
109+
System::Call "*$R9(i,i,i.r0,i,i,i.r1,i.r2,i.r3,i,&w256.r4)" ; Get next module
110+
111+
;free:
112+
System::Free $R9
113+
System::Call "Kernel32::CloseToolhelp32Snapshot(i R0)"
114+
115+
;===============
116+
;now get full path and commandline
117+
118+
System::Call "Kernel32::OpenProcess(i 1040, i 0, i r0)i .R0"
119+
120+
StrCmp $R0 0 end
121+
122+
IntOp $R8 0 + 256
123+
System::Call "psapi::GetModuleFileNameExW(i R0,i 0,t .r5, *i $R8)i .R1"
124+
125+
end:
126+
Pop $R8
127+
Pop $R9
128+
Pop $R1
129+
Pop $R0
130+
Exch $5
131+
Exch 1
132+
Exch $4
133+
Exch 2
134+
Exch $3
135+
Exch 3
136+
Exch $2
137+
Exch 4
138+
Pop $1
139+
Exch 4
140+
Exch $0
141+
Exch 5
142+
Pop $R3
143+
!macroend ;FUNC_GETPROCESSINFO
144+
145+
!ifndef BUILD_UNINSTALLER
146+
Function _GetProcessInfo
147+
!insertmacro FUNC_GETPROCESSINFO
148+
FunctionEnd
149+
!endif
150+
151+
!ifdef BUILD_UNINSTALLER
152+
Function un._GetProcessInfo
153+
!insertmacro FUNC_GETPROCESSINFO
154+
FunctionEnd
155+
!endif
156+
157+
!endif ;GETPROCESSINFO_INCLUDED

0 commit comments

Comments
 (0)