Add installer new option '/closeRunningNpp'
New Notepad++ NSIS installer cmdline option. If specified on the cmdline, it first tries to use the usual app-closing by sending the WM_CLOSE message to the running Notepad++. If that standard closing fails, it uses consequently the forceful TerminateProcess WINAPI way. Partially fix the #8514, followup of the #14251. Close #15230pull/15267/head
parent
aea78d71e2
commit
83f1195bc1
|
@ -114,6 +114,7 @@ InstType "Minimalist"
|
||||||
|
|
||||||
Var diffArchDir2Remove
|
Var diffArchDir2Remove
|
||||||
Var noUpdater
|
Var noUpdater
|
||||||
|
Var closeRunningNpp
|
||||||
|
|
||||||
|
|
||||||
!ifdef ARCH64 || ARCHARM64
|
!ifdef ARCH64 || ARCHARM64
|
||||||
|
@ -150,6 +151,21 @@ Function .onInit
|
||||||
;
|
;
|
||||||
; --- PATCH END ---
|
; --- PATCH END ---
|
||||||
|
|
||||||
|
; check for the possible "/closeRunningNpp" cmdline option 1st
|
||||||
|
${GetParameters} $R0
|
||||||
|
${GetOptions} $R0 "/closeRunningNpp" $R1 ; case insensitive
|
||||||
|
IfErrors 0 closeRunningNppYes
|
||||||
|
StrCpy $closeRunningNpp "false"
|
||||||
|
Goto closeRunningNppCheckDone
|
||||||
|
closeRunningNppYes:
|
||||||
|
StrCpy $closeRunningNpp "true"
|
||||||
|
closeRunningNppCheckDone:
|
||||||
|
${If} $closeRunningNpp == "true"
|
||||||
|
; First try to use the usual app-closing by sending the WM_CLOSE.
|
||||||
|
; If that closing fails, use the forceful TerminateProcess way.
|
||||||
|
!insertmacro FindAndCloseOrTerminateRunningNpp ; this has to precede the following silent mode Notepad++ instance mutex check
|
||||||
|
${EndIf}
|
||||||
|
|
||||||
; handle the possible Silent Mode (/S) & already running Notepad++ (without this an incorrect partial installation is possible)
|
; handle the possible Silent Mode (/S) & already running Notepad++ (without this an incorrect partial installation is possible)
|
||||||
IfSilent 0 notInSilentMode
|
IfSilent 0 notInSilentMode
|
||||||
System::Call 'kernel32::OpenMutex(i 0x100000, b 0, t "nppInstance") i .R0'
|
System::Call 'kernel32::OpenMutex(i 0x100000, b 0, t "nppInstance") i .R0'
|
||||||
|
|
|
@ -208,3 +208,62 @@ Function writeInstallInfoInRegistry
|
||||||
WriteUninstaller "$INSTDIR\uninstall.exe"
|
WriteUninstaller "$INSTDIR\uninstall.exe"
|
||||||
FunctionEnd
|
FunctionEnd
|
||||||
|
|
||||||
|
|
||||||
|
!define RUNPROC_WND_CLASS "Notepad++"
|
||||||
|
!define RUNPROC_WAIT_FOR_EXIT_MAX_MS 5000 ; 5 seconds max
|
||||||
|
!define RUNPROC_SYNC_TERM 0x00100001 ; dwDesiredAccess ... PROCESS_TERMINATE | SYNCHRONIZE
|
||||||
|
!include WinMessages.nsh
|
||||||
|
|
||||||
|
!macro FindAndCloseOrTerminateRunningNpp
|
||||||
|
; to not influence the global NSIS vars used here, push them on the stack and pop them out at the end
|
||||||
|
Push $0 ; running process main HWND
|
||||||
|
Push $1 ; result of the waiting for the running process object
|
||||||
|
Push $2 ; running process HANDLE
|
||||||
|
Push $3 ; possible WIN32 error code (the GetLastError() result)
|
||||||
|
|
||||||
|
findRunningProcessByClassName:
|
||||||
|
FindWindow $0 '${RUNPROC_WND_CLASS}' ''
|
||||||
|
IntPtrCmp $0 0 processNotRunning
|
||||||
|
IsWindow $0 0 processNotRunning
|
||||||
|
|
||||||
|
IfSilent skipDetailPrint 0
|
||||||
|
DetailPrint "Closing the ${RUNPROC_WND_CLASS} app running..."
|
||||||
|
skipDetailPrint:
|
||||||
|
|
||||||
|
System::Call 'user32.dll::GetWindowThreadProcessId(i r0, *i .r1) i .r2'
|
||||||
|
System::Call 'kernel32.dll::OpenProcess(i ${RUNPROC_SYNC_TERM}, i 0, i r1) p .r2 ?e' ; ?e ... the NSIS system plugin will additionally put the GetLastError() code on top of the stack
|
||||||
|
pop $3 ; a possible WIN32 error code will be here
|
||||||
|
IntPtrCmp $2 0 openProcessFail
|
||||||
|
|
||||||
|
System::Call 'user32.dll::PostMessage(i $0, i ${WM_CLOSE}, i 0, i 0)'
|
||||||
|
System::Call 'kernel32.dll::WaitForSingleObject(i r2, i ${RUNPROC_WAIT_FOR_EXIT_MAX_MS}) i .r1'
|
||||||
|
IntCmp $1 0 closeProcessHandle ; 0 == WAIT_OBJECT_0 (signaled state of the process to close...)
|
||||||
|
|
||||||
|
; process could not be stopped by the usual WM_CLOSE way, so use a hard termination instead
|
||||||
|
IfSilent terminateProcess 0
|
||||||
|
MessageBox MB_YESNOCANCEL|MB_ICONEXCLAMATION "Installer cannot stop the running ${RUNPROC_WND_CLASS} by usual closing request.$\n$\nDo you want to forcefully terminate that process?" /SD IDYES IDYES terminateProcess IDNO closeProcessHandle
|
||||||
|
; cancel was selected, so close the opened running process handle and quit immediately
|
||||||
|
System::Call 'kernel32.dll::CloseHandle(i r2) i .r1'
|
||||||
|
SetErrorLevel 5 ; set an exit code > 0 otherwise the installer returns 0 aka SUCCESS (5 == ERROR_ACCESS_DENIED)
|
||||||
|
Quit ; installer will end
|
||||||
|
|
||||||
|
terminateProcess:
|
||||||
|
System::Call 'kernel32.dll::TerminateProcess(i r2, i 0) i .r1'
|
||||||
|
|
||||||
|
closeProcessHandle:
|
||||||
|
System::Call 'kernel32.dll::CloseHandle(i r2) i .r1'
|
||||||
|
goto findRunningProcessByClassName ; loop, we need to check for all the possible instances of the process running
|
||||||
|
|
||||||
|
openProcessFail:
|
||||||
|
IfSilent skipOpenProcessFailMessage 0
|
||||||
|
MessageBox MB_OK|MB_ICONSTOP "Installer cannot stop the running ${RUNPROC_WND_CLASS}.\n\nOpenProcess WINAPI failed! (error code: $3)"
|
||||||
|
skipOpenProcessFailMessage:
|
||||||
|
SetErrorLevel $3 ; set an exit code > 0 otherwise the installer returns 0 aka SUCCESS
|
||||||
|
Quit ; installer will end
|
||||||
|
|
||||||
|
processNotRunning:
|
||||||
|
Pop $3
|
||||||
|
Pop $2
|
||||||
|
Pop $1
|
||||||
|
Pop $0
|
||||||
|
!macroend
|
||||||
|
|
Loading…
Reference in New Issue