Windows installer: terminate Imager if running

- Try to gracefully close any running Imager instance by sending
a window message. Should close it automatically if Imager is not
actually writing something.

If Imager does not close within 2 seconds, prompt user to ask
if it should be terminated less gracefully.

- Change installer executable name (setup.exe -> image-<version>.exe).
- Prevent UAC prompt during compiling installer.
This commit is contained in:
Floris Bos 2020-07-21 15:25:31 +02:00
parent 04595d28c6
commit 65c6377052

View file

@ -1,8 +1,3 @@
!define INSTALLER_NAME "setup.exe"
!ifndef INNER
!finalize '"c:\Program Files (x86)\Microsoft SDKs\ClickOnce\SignTool\signtool.exe" sign /tr http://timestamp.digicert.com /td sha256 /fd sha256 /a "%1"'
!endif
############################################################################################
# NSIS Installation Script created by NSIS Quick Setup Script Generator v1.09.18
# Entirely Edited with NullSoft Scriptable Installation System
@ -13,6 +8,7 @@
!define COMP_NAME "Raspberry Pi"
#!define WEB_SITE "https://www.raspberrypi.org/"
!define VERSION "@IMAGER_VERSION_STR@"
!define INSTALLER_NAME "imager-${VERSION}.exe"
!define COPYRIGHT "Raspberry Pi"
!define DESCRIPTION "Raspberry Pi Imager"
!define MAIN_APP_EXE "rpi-imager.exe"
@ -21,6 +17,12 @@
!define REG_APP_PATH "Software\Microsoft\Windows\CurrentVersion\App Paths\${MAIN_APP_EXE}"
!define UNINSTALL_PATH "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APP_NAME}"
# Window to close if running
!define EXE_TO_TERMINATE "rpi-imager.exe"
LangString termMsg 1033 "Raspberry Pi Imager seems to be running and busy.$\nDo you want to terminate process?"
LangString stopMsg 1033 "Stopping Raspberry Pi Imager"
######################################################################
VIProductVersion "@IMAGER_VERSION_MAJOR@.@IMAGER_VERSION_MINOR@.0.0"
@ -59,7 +61,7 @@ InstallDir "$PROGRAMFILES\Raspberry Pi Imager"
; So now run that installer we just created as %TEMP%\tempinstaller.exe. Since it
; calls quit the return value isn't zero.
!system "$%TEMP%\tempinstaller.exe" = 2
!system 'set __COMPAT_LAYER=RunAsInvoker &"$%TEMP%\tempinstaller.exe"' = 2
; That will have written an uninstaller binary for us. Now we sign it with your
; favorite code signing tool.
@ -68,8 +70,9 @@ InstallDir "$PROGRAMFILES\Raspberry Pi Imager"
; Good. Now we can carry on writing the real installer.
OutFile "setup.exe"
OutFile "${INSTALLER_NAME}"
SetCompressor /SOLID lzma
!finalize '"c:\Program Files (x86)\Microsoft SDKs\ClickOnce\SignTool\signtool.exe" sign /tr http://timestamp.digicert.com /td sha256 /fd sha256 /a "%1"'
!endif
###
@ -111,8 +114,97 @@ InstallDir "$PROGRAMFILES\Raspberry Pi Imager"
######################################################################
!include WinMessages.nsh
!include Logiclib.nsh
!macro FindWindowOfExe Exe
Push $1
Push $2
Push $3
Push $R0
Push $R1
SetPluginUnload alwaysoff
Push "0" ; Result code
System::Get "(i.r1, i) iss"
Pop $R0
System::Call "user32::EnumWindows(k R0, i) i.s"
loop:
Pop $0
StrCmp $0 "callback1" 0 doneloop
System::Call 'user32.dll::GetWindowThreadProcessId(i r1, *i .r3) i .r2'
System::Call 'kernel32.dll::OpenProcess(i 1040, i 0, i r3) i .r2'
${IfNot} $2 = 0
System::Alloc 1024
Pop $R1
System::Call "Psapi::EnumProcessModules(i r2, i R1, i 1024, *i .r3) i .r0"
${IfNot} $0 = 0
System::Call "*$R1(i .r0)"
System::Call "Psapi::GetModuleBaseName(i r2, i r0, t .r3, i ${NSIS_MAX_STRLEN}) i .r0"
${IfNot} $0 = 0
${If} $3 == "${Exe}"
# Only replace result value if it is first match
Pop $3
${If} $3 == 0
Push $1
${Else}
Push $3
${EndIf}
${EndIf}
${EndIf}
${EndIf}
System::Free $R1
System::Call "kernel32::CloseHandle(i r2)"
${EndIf}
Push 1
System::Call "$R0"
Goto loop
doneloop:
SetPluginUnload manual
System::Free $R0
Pop $0
Pop $R1
Pop $R0
Pop $3
Pop $2
Pop $1
!macroend
!macro TerminateApp
Push $0 ; window handle
Push $1
Push $2 ; process handle
DetailPrint "$(stopMsg)"
#FindWindow $0 '' '${WND_TITLE}'
!insertmacro FindWindowOfExe '${EXE_TO_TERMINATE}'
IntCmp $0 0 done
System::Call 'user32.dll::GetWindowThreadProcessId(i r0, *i .r1) i .r2'
System::Call 'kernel32.dll::OpenProcess(i 0x00100001, i 0, i r1) i .r2'
SendMessage $0 ${WM_CLOSE} 0 0 /TIMEOUT=2000
System::Call 'kernel32.dll::WaitForSingleObject(i r2, i 2000) i .r1'
IntCmp $1 0 close
MessageBox MB_YESNOCANCEL|MB_ICONEXCLAMATION "$(termMsg)" /SD IDYES IDYES terminate IDNO close
System::Call 'kernel32.dll::CloseHandle(i r2) i .r1'
Quit
terminate:
System::Call 'kernel32.dll::TerminateProcess(i r2, i 0) i .r1'
close:
System::Call 'kernel32.dll::CloseHandle(i r2) i .r1'
done:
Pop $2
Pop $1
Pop $0
!macroend
######################################################################
Section -MainProgram
${INSTALL_TYPE}
!insertmacro TerminateApp
SetOverwrite ifnewer
SetOutPath "$INSTDIR"
File "deploy\D3Dcompiler_47.dll"