Skip to content

Commit 0540a91

Browse files
Filip Mösnerpanther7
authored andcommitted
feat(nsis): terminate only processes running in installation folder
Modified the process termination logic in NSIS scripts to only kill application processes that are running from the installation directory. This prevents accidental termination of processes with the same name running from other locations during installation or update.
1 parent f200ddb commit 0540a91

File tree

2 files changed

+74
-24
lines changed

2 files changed

+74
-24
lines changed

.changeset/flat-trees-return.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"app-builder-lib": patch
3+
---
4+
5+
feat(nsis): terminate only processes running in installation folder

packages/app-builder-lib/templates/nsis/include/allowOnlyOneInstallerInstance.nsh

Lines changed: 69 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -30,22 +30,76 @@
3030
!macroend
3131

3232
!macro CHECK_APP_RUNNING
33-
!ifmacrodef customCheckAppRunning
34-
!insertmacro customCheckAppRunning
33+
Var /GLOBAL CmdPath
34+
Var /GLOBAL FindPath
35+
Var /GLOBAL PowerShellPath
36+
!ifmacrodef customCheckAppRunning
37+
!insertmacro customCheckAppRunning
38+
!else
39+
StrCpy $CmdPath "$SYSDIR\cmd.exe"
40+
StrCpy $FindPath "$SYSDIR\find.exe"
41+
StrCpy $PowerShellPath "pwsh" ; PowerShell Core (7+)
42+
# StrCpy $PowerShellPath "$SYSDIR\WindowsPowerShell\v1.0\powershell.exe" ; actually broken with PowerShell 5.1 (and below), because some Paths are empty.
43+
!insertmacro IS_POWERSHELL_AVAILABLE
44+
!insertmacro _CHECK_APP_RUNNING
45+
!endif
46+
!macroend
47+
48+
!macro IS_POWERSHELL_AVAILABLE
49+
Var /GLOBAL IsPowerShellAvailable ; 0 = available, 1 = not available
50+
# Try running PowerShell with a simple command
51+
nsExec::Exec `"$PowerShellPath" -Command "exit 0"`
52+
Pop $0 # Return code (0 = success, other = error)
53+
54+
${if} $0 == 0
55+
# PowerShell is available, check if it's not blocked by policies
56+
nsExec::Exec `"$PowerShellPath" -Command "if ((Get-ExecutionPolicy -Scope Process) -eq 'Restricted') { exit 1 } else { exit 0 }"`
57+
Pop $0
58+
${else}
59+
StrCpy $0 1
60+
${endIf}
61+
62+
StrCpy $IsPowerShellAvailable $0
63+
!macroend
64+
65+
!macro FIND_PROCESS _FILE _RETURN
66+
${if} $IsPowerShellAvailable == 0
67+
nsExec::Exec `"$PowerShellPath" -C "if ((Get-Process | ? {$$_.Path -and $$_.Path.StartsWith('$INSTDIR', 'CurrentCultureIgnoreCase')}).Count -gt 0) { exit 0 } else { exit 1 }"`
68+
Pop ${_RETURN}
69+
${else}
70+
!ifdef INSTALL_MODE_PER_ALL_USERS
71+
${nsProcess::FindProcess} "${_FILE}" ${_RETURN}
3572
!else
36-
!insertmacro _CHECK_APP_RUNNING
73+
# find process owned by current user
74+
nsExec::Exec `"$CmdPath" /c tasklist /FI "USERNAME eq %USERNAME%" /FI "IMAGENAME eq ${_FILE}" /FO csv | "$FindPath" "${_FILE}"`
75+
Pop ${_RETURN}
3776
!endif
77+
${endIf}
3878
!macroend
3979

40-
!macro FIND_PROCESS _FILE _ERR
41-
!ifdef INSTALL_MODE_PER_ALL_USERS
42-
${nsProcess::FindProcess} "${_FILE}" ${_ERR}
43-
!else
44-
# find process owned by current user
45-
nsExec::Exec `"$SYSDIR\cmd.exe" /c tasklist /FI "USERNAME eq %USERNAME%" /FI "IMAGENAME eq ${_FILE}" /FO csv | "$SYSDIR\find.exe" "${_FILE}"`
46-
Pop ${_ERR}
47-
!endif
48-
!macroend
80+
!macro KILL_PROCESS _FILE _FORCE
81+
Push $0
82+
${if} ${_FORCE} == 1
83+
${if} $IsPowerShellAvailable == 0
84+
StrCpy $0 "-Force"
85+
${else}
86+
StrCpy $0 "/f"
87+
${endIf}
88+
${else}
89+
StrCpy $0 ""
90+
${endIf}
91+
92+
${if} $IsPowerShellAvailable == 0
93+
nsExec::Exec `"$PowerShellPath" -Command "Get-Process | ? {$$_.Path -and $$_.Path.StartsWith('$INSTDIR', 'CurrentCultureIgnoreCase')} | Stop-Process $0"`
94+
${else}
95+
!ifdef INSTALL_MODE_PER_ALL_USERS
96+
nsExec::Exec `taskkill /im "${_FILE}" /fi "PID ne $pid"`
97+
!else
98+
nsExec::Exec `"$CmdPath" /c taskkill $0 /IM "${_FILE}" /FI "PID ne $pid" /FI "USERNAME eq %USERNAME%"`
99+
!endif
100+
${endIf}
101+
Pop $0
102+
!macroend
49103

50104
!macro _CHECK_APP_RUNNING
51105
${GetProcessInfo} 0 $pid $1 $2 $3 $4
@@ -69,12 +123,7 @@
69123

70124
DetailPrint `Closing running "${PRODUCT_NAME}"...`
71125

72-
# https://github.com/electron-userland/electron-builder/issues/2516#issuecomment-372009092
73-
!ifdef INSTALL_MODE_PER_ALL_USERS
74-
nsExec::Exec `taskkill /im "${APP_EXECUTABLE_FILENAME}" /fi "PID ne $pid"`
75-
!else
76-
nsExec::Exec `"$SYSDIR\cmd.exe" /c taskkill /im "${APP_EXECUTABLE_FILENAME}" /fi "PID ne $pid" /fi "USERNAME eq %USERNAME%"`
77-
!endif
126+
!insertmacro KILL_PROCESS "${APP_EXECUTABLE_FILENAME}" 0
78127
# to ensure that files are not "in-use"
79128
Sleep 300
80129

@@ -88,13 +137,9 @@
88137
${if} $R0 == 0
89138
# wait to give a chance to exit gracefully
90139
Sleep 1000
91-
!ifdef INSTALL_MODE_PER_ALL_USERS
92-
nsExec::Exec `taskkill /f /im "${APP_EXECUTABLE_FILENAME}" /fi "PID ne $pid"`
93-
!else
94-
nsExec::Exec `"$SYSDIR\cmd.exe" /c taskkill /f /im "${APP_EXECUTABLE_FILENAME}" /fi "PID ne $pid" /fi "USERNAME eq %USERNAME%"`
95-
!endif
140+
!insertmacro KILL_PROCESS "${APP_EXECUTABLE_FILENAME}" 1 # 1 = force kill
96141
!insertmacro FIND_PROCESS "${APP_EXECUTABLE_FILENAME}" $R0
97-
${If} $R0 == 0
142+
${if} $R0 == 0
98143
DetailPrint `Waiting for "${PRODUCT_NAME}" to close.`
99144
Sleep 2000
100145
${else}

0 commit comments

Comments
 (0)