; This file is copied from https://github.com/tauri-apps/tauri/blob/tauri-v1.5/tooling/bundler/src/bundle/windows/templates/installer.nsi ; and edit to fit the needs of the project. the latest tauri 2.x has a different base nsi script. Unicode true ; Set the compression algorithm. Default is LZMA. !if "{{compression}}" == "" SetCompressor /SOLID lzma !else SetCompressor /SOLID "{{compression}}" !endif !include MUI2.nsh !include FileFunc.nsh !include x64.nsh !include WordFunc.nsh !include "StrFunc.nsh" !include "Win\COM.nsh" !include "Win\Propkey.nsh" !addplugindir "$%AppData%\Local\NSIS\" ${StrCase} ${StrLoc} !define MANUFACTURER "{{manufacturer}}" !define PRODUCTNAME "{{product_name}}" !define VERSION "{{version}}" !define VERSIONWITHBUILD "{{version_with_build}}" !define SHORTDESCRIPTION "{{short_description}}" !define INSTALLMODE "{{install_mode}}" !define LICENSE "{{license}}" !define INSTALLERICON "{{installer_icon}}" !define SIDEBARIMAGE "{{sidebar_image}}" !define HEADERIMAGE "{{header_image}}" !define MAINBINARYNAME "{{main_binary_name}}" !define MAINBINARYSRCPATH "{{main_binary_path}}" !define BUNDLEID "{{bundle_id}}" !define COPYRIGHT "{{copyright}}" !define OUTFILE "{{out_file}}" !define ARCH "{{arch}}" !define PLUGINSPATH "{{additional_plugins_path}}" !define ALLOWDOWNGRADES "{{allow_downgrades}}" !define DISPLAYLANGUAGESELECTOR "{{display_language_selector}}" !define INSTALLWEBVIEW2MODE "{{install_webview2_mode}}" !define WEBVIEW2INSTALLERARGS "{{webview2_installer_args}}" !define WEBVIEW2BOOTSTRAPPERPATH "{{webview2_bootstrapper_path}}" !define WEBVIEW2INSTALLERPATH "{{webview2_installer_path}}" !define UNINSTKEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCTNAME}" !define MANUPRODUCTKEY "Software\${MANUFACTURER}\${PRODUCTNAME}" !define UNINSTALLERSIGNCOMMAND "{{uninstaller_sign_cmd}}" !define ESTIMATEDSIZE "{{estimated_size}}" Name "${PRODUCTNAME}" BrandingText "${COPYRIGHT}" OutFile "${OUTFILE}" VIProductVersion "${VERSIONWITHBUILD}" VIAddVersionKey "ProductName" "${PRODUCTNAME}" VIAddVersionKey "FileDescription" "${SHORTDESCRIPTION}" VIAddVersionKey "LegalCopyright" "${COPYRIGHT}" VIAddVersionKey "FileVersion" "${VERSION}" VIAddVersionKey "ProductVersion" "${VERSION}" ; Plugins path, currently exists for linux only !if "${PLUGINSPATH}" != "" !addplugindir "${PLUGINSPATH}" !endif !if "${UNINSTALLERSIGNCOMMAND}" != "" !uninstfinalize '${UNINSTALLERSIGNCOMMAND}' !endif ; Handle install mode, `perUser`, `perMachine` or `both` !if "${INSTALLMODE}" == "perMachine" RequestExecutionLevel highest !endif !if "${INSTALLMODE}" == "currentUser" RequestExecutionLevel user !endif !if "${INSTALLMODE}" == "both" !define MULTIUSER_MUI !define MULTIUSER_INSTALLMODE_INSTDIR "${PRODUCTNAME}" !define MULTIUSER_INSTALLMODE_COMMANDLINE !if "${ARCH}" == "x64" !define MULTIUSER_USE_PROGRAMFILES64 !else if "${ARCH}" == "arm64" !define MULTIUSER_USE_PROGRAMFILES64 !endif !define MULTIUSER_INSTALLMODE_DEFAULT_REGISTRY_KEY "${UNINSTKEY}" !define MULTIUSER_INSTALLMODE_DEFAULT_REGISTRY_VALUENAME "CurrentUser" !define MULTIUSER_INSTALLMODEPAGE_SHOWUSERNAME !define MULTIUSER_INSTALLMODE_FUNCTION RestorePreviousInstallLocation !define MULTIUSER_EXECUTIONLEVEL Highest !include MultiUser.nsh !endif ; installer icon !if "${INSTALLERICON}" != "" !define MUI_ICON "${INSTALLERICON}" !endif ; installer sidebar image !if "${SIDEBARIMAGE}" != "" !define MUI_WELCOMEFINISHPAGE_BITMAP "${SIDEBARIMAGE}" !endif ; installer header image !if "${HEADERIMAGE}" != "" !define MUI_HEADERIMAGE !define MUI_HEADERIMAGE_BITMAP "${HEADERIMAGE}" !endif ; Define registry key to store installer language !define MUI_LANGDLL_REGISTRY_ROOT "HKCU" !define MUI_LANGDLL_REGISTRY_KEY "${MANUPRODUCTKEY}" !define MUI_LANGDLL_REGISTRY_VALUENAME "Installer Language" ; Installer pages, must be ordered as they appear ; 1. Welcome Page !define MUI_PAGE_CUSTOMFUNCTION_PRE SkipIfPassive !insertmacro MUI_PAGE_WELCOME ; 2. License Page (if defined) !if "${LICENSE}" != "" !define MUI_PAGE_CUSTOMFUNCTION_PRE SkipIfPassive !insertmacro MUI_PAGE_LICENSE "${LICENSE}" !endif ; 3. Install mode (if it is set to `both`) !if "${INSTALLMODE}" == "both" !define MUI_PAGE_CUSTOMFUNCTION_PRE SkipIfPassive !insertmacro MULTIUSER_PAGE_INSTALLMODE !endif ; 4. Custom page to ask user if he wants to reinstall/uninstall ; only if a previous installtion was detected Var ReinstallPageCheck Page custom PageReinstall PageLeaveReinstall Function PageReinstall ; Uninstall previous WiX installation if exists. ; ; A WiX installer stores the isntallation info in registry ; using a UUID and so we have to loop through all keys under ; `HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall` ; and check if `DisplayName` and `Publisher` keys match ${PRODUCTNAME} and ${MANUFACTURER} ; ; This has a potentional issue that there maybe another installation that matches ; our ${PRODUCTNAME} and ${MANUFACTURER} but wasn't installed by our WiX installer, ; however, this should be fine since the user will have to confirm the uninstallation ; and they can chose to abort it if doesn't make sense. StrCpy $0 0 wix_loop: EnumRegKey $1 HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall" $0 StrCmp $1 "" wix_done ; Exit loop if there is no more keys to loop on IntOp $0 $0 + 1 ReadRegStr $R0 HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$1" "DisplayName" ReadRegStr $R1 HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$1" "Publisher" StrCmp "$R0$R1" "${PRODUCTNAME}${MANUFACTURER}" 0 wix_loop ReadRegStr $R0 HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$1" "UninstallString" ${StrCase} $R1 $R0 "L" ${StrLoc} $R0 $R1 "msiexec" ">" StrCmp $R0 0 0 wix_done StrCpy $R7 "wix" StrCpy $R6 "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$1" Goto compare_version wix_done: ; Check if there is an existing installation, if not, abort the reinstall page ReadRegStr $R0 SHCTX "${UNINSTKEY}" "" ReadRegStr $R1 SHCTX "${UNINSTKEY}" "UninstallString" ${IfThen} "$R0$R1" == "" ${|} Abort ${|} ; Compare this installar version with the existing installation ; and modify the messages presented to the user accordingly compare_version: StrCpy $R4 "$(older)" ${If} $R7 == "wix" ReadRegStr $R0 HKLM "$R6" "DisplayVersion" ${Else} ReadRegStr $R0 SHCTX "${UNINSTKEY}" "DisplayVersion" ${EndIf} ${IfThen} $R0 == "" ${|} StrCpy $R4 "$(unknown)" ${|} nsis_tauri_utils::SemverCompare "${VERSION}" $R0 Pop $R0 ; Reinstalling the same version ${If} $R0 == 0 StrCpy $R1 "$(alreadyInstalledLong)" StrCpy $R2 "$(addOrReinstall)" StrCpy $R3 "$(uninstallApp)" !insertmacro MUI_HEADER_TEXT "$(alreadyInstalled)" "$(chooseMaintenanceOption)" StrCpy $R5 "2" ; Upgrading ${ElseIf} $R0 == 1 StrCpy $R1 "$(olderOrUnknownVersionInstalled)" StrCpy $R2 "$(uninstallBeforeInstalling)" StrCpy $R3 "$(dontUninstall)" !insertmacro MUI_HEADER_TEXT "$(alreadyInstalled)" "$(choowHowToInstall)" StrCpy $R5 "1" ; Downgrading ${ElseIf} $R0 == -1 StrCpy $R1 "$(newerVersionInstalled)" StrCpy $R2 "$(uninstallBeforeInstalling)" !if "${ALLOWDOWNGRADES}" == "true" StrCpy $R3 "$(dontUninstall)" !else StrCpy $R3 "$(dontUninstallDowngrade)" !endif !insertmacro MUI_HEADER_TEXT "$(alreadyInstalled)" "$(choowHowToInstall)" StrCpy $R5 "1" ${Else} Abort ${EndIf} Call SkipIfPassive nsDialogs::Create 1018 Pop $R4 ${IfThen} $(^RTL) == 1 ${|} nsDialogs::SetRTL $(^RTL) ${|} ${NSD_CreateLabel} 0 0 100% 24u $R1 Pop $R1 ${NSD_CreateRadioButton} 30u 50u -30u 8u $R2 Pop $R2 ${NSD_OnClick} $R2 PageReinstallUpdateSelection ${NSD_CreateRadioButton} 30u 70u -30u 8u $R3 Pop $R3 ; disable this radio button if downgrading and downgrades are disabled !if "${ALLOWDOWNGRADES}" == "false" ${IfThen} $R0 == -1 ${|} EnableWindow $R3 0 ${|} !endif ${NSD_OnClick} $R3 PageReinstallUpdateSelection ; Check the first radio button if this the first time ; we enter this page or if the second button wasn't ; selected the last time we were on this page ${If} $ReinstallPageCheck != 2 SendMessage $R2 ${BM_SETCHECK} ${BST_CHECKED} 0 ${Else} SendMessage $R3 ${BM_SETCHECK} ${BST_CHECKED} 0 ${EndIf} ${NSD_SetFocus} $R2 nsDialogs::Show FunctionEnd Function PageReinstallUpdateSelection ${NSD_GetState} $R2 $R1 ${If} $R1 == ${BST_CHECKED} StrCpy $ReinstallPageCheck 1 ${Else} StrCpy $ReinstallPageCheck 2 ${EndIf} FunctionEnd Function PageLeaveReinstall ${NSD_GetState} $R2 $R1 ; $R5 holds whether we are reinstalling the same version or not ; $R5 == "1" -> different versions ; $R5 == "2" -> same version ; ; $R1 holds the radio buttons state. its meaning is dependant on the context StrCmp $R5 "1" 0 +2 ; Existing install is not the same version? StrCmp $R1 "1" reinst_uninstall reinst_done ; $R1 == "1", then user chose to uninstall existing version, otherwise skip uninstalling StrCmp $R1 "1" reinst_done ; Same version? skip uninstalling reinst_uninstall: HideWindow ClearErrors ${If} $R7 == "wix" ReadRegStr $R1 HKLM "$R6" "UninstallString" ExecWait '$R1' $0 ${Else} ReadRegStr $4 SHCTX "${MANUPRODUCTKEY}" "" ReadRegStr $R1 SHCTX "${UNINSTKEY}" "UninstallString" ExecWait '$R1 /P _?=$4' $0 ${EndIf} BringToFront ${IfThen} ${Errors} ${|} StrCpy $0 2 ${|} ; ExecWait failed, set fake exit code ${If} $0 <> 0 ${OrIf} ${FileExists} "$INSTDIR\${MAINBINARYNAME}.exe" ${If} $0 = 1 ; User aborted uninstaller? StrCmp $R5 "2" 0 +2 ; Is the existing install the same version? Quit ; ...yes, already installed, we are done Abort ${EndIf} MessageBox MB_ICONEXCLAMATION "$(unableToUninstall)" Abort ${Else} StrCpy $0 $R1 1 ${IfThen} $0 == '"' ${|} StrCpy $R1 $R1 -1 1 ${|} ; Strip quotes from UninstallString Delete $R1 RMDir $INSTDIR ${EndIf} reinst_done: FunctionEnd ; 5. Choose install directoy page !define MUI_PAGE_CUSTOMFUNCTION_PRE SkipIfPassive !insertmacro MUI_PAGE_DIRECTORY ; 6. Start menu shortcut page !define MUI_PAGE_CUSTOMFUNCTION_PRE SkipIfPassive Var AppStartMenuFolder !insertmacro MUI_PAGE_STARTMENU Application $AppStartMenuFolder ; 7. Installation page !insertmacro MUI_PAGE_INSTFILES ; 8. Finish page ; ; Don't auto jump to finish page after installation page, ; because the installation page has useful info that can be used debug any issues with the installer. !define MUI_FINISHPAGE_NOAUTOCLOSE ; Use show readme button in the finish page as a button create a desktop shortcut !define MUI_FINISHPAGE_SHOWREADME !define MUI_FINISHPAGE_SHOWREADME_TEXT "$(createDesktop)" !define MUI_FINISHPAGE_SHOWREADME_FUNCTION CreateDesktopShortcut ; Show run app after installation. !define MUI_FINISHPAGE_RUN "$INSTDIR\${MAINBINARYNAME}.exe" !define MUI_PAGE_CUSTOMFUNCTION_PRE SkipIfPassive !insertmacro MUI_PAGE_FINISH ; Uninstaller Pages ; 1. Confirm uninstall page Var DeleteAppDataCheckbox Var DeleteAppDataCheckboxState !define /ifndef WS_EX_LAYOUTRTL 0x00400000 !define MUI_PAGE_CUSTOMFUNCTION_SHOW un.ConfirmShow Function un.ConfirmShow FindWindow $1 "#32770" "" $HWNDPARENT ; Find inner dialog ${If} $(^RTL) == 1 System::Call 'USER32::CreateWindowEx(i${__NSD_CheckBox_EXSTYLE}|${WS_EX_LAYOUTRTL},t"${__NSD_CheckBox_CLASS}",t "$(deleteAppData)",i${__NSD_CheckBox_STYLE},i 50,i 100,i 400, i 25,i$1,i0,i0,i0)i.s' ${Else} System::Call 'USER32::CreateWindowEx(i${__NSD_CheckBox_EXSTYLE},t"${__NSD_CheckBox_CLASS}",t "$(deleteAppData)",i${__NSD_CheckBox_STYLE},i 0,i 100,i 400, i 25,i$1,i0,i0,i0)i.s' ${EndIf} Pop $DeleteAppDataCheckbox SendMessage $HWNDPARENT ${WM_GETFONT} 0 0 $1 SendMessage $DeleteAppDataCheckbox ${WM_SETFONT} $1 1 FunctionEnd !define MUI_PAGE_CUSTOMFUNCTION_LEAVE un.ConfirmLeave Function un.ConfirmLeave SendMessage $DeleteAppDataCheckbox ${BM_GETCHECK} 0 0 $DeleteAppDataCheckboxState FunctionEnd !insertmacro MUI_UNPAGE_CONFIRM ; 2. Uninstalling Page !insertmacro MUI_UNPAGE_INSTFILES ;Languages {{#each languages}} !insertmacro MUI_LANGUAGE "{{this}}" {{/each}} !insertmacro MUI_RESERVEFILE_LANGDLL {{#each language_files}} !include "{{this}}" {{/each}} !macro SetContext !if "${INSTALLMODE}" == "currentUser" SetShellVarContext current !else if "${INSTALLMODE}" == "perMachine" SetShellVarContext all !endif ${If} ${RunningX64} !if "${ARCH}" == "x64" SetRegView 64 !else if "${ARCH}" == "arm64" SetRegView 64 !else SetRegView 32 !endif ${EndIf} !macroend Var PassiveMode Function .onInit ${GetOptions} $CMDLINE "/P" $PassiveMode IfErrors +2 0 StrCpy $PassiveMode 1 !if "${DISPLAYLANGUAGESELECTOR}" == "true" !insertmacro MUI_LANGDLL_DISPLAY !endif !insertmacro SetContext ${If} $INSTDIR == "" ; Set default install location !if "${INSTALLMODE}" == "perMachine" ${If} ${RunningX64} !if "${ARCH}" == "x64" StrCpy $INSTDIR "$PROGRAMFILES64\${PRODUCTNAME}" !else if "${ARCH}" == "arm64" StrCpy $INSTDIR "$PROGRAMFILES64\${PRODUCTNAME}" !else StrCpy $INSTDIR "$PROGRAMFILES\${PRODUCTNAME}" !endif ${Else} StrCpy $INSTDIR "$PROGRAMFILES\${PRODUCTNAME}" ${EndIf} !else if "${INSTALLMODE}" == "currentUser" StrCpy $INSTDIR "$LOCALAPPDATA\${PRODUCTNAME}" !endif Call RestorePreviousInstallLocation ${EndIf} !if "${INSTALLMODE}" == "both" !insertmacro MULTIUSER_INIT !endif FunctionEnd !macro CheckAllVergeProcesses ; Check if clash-verge-service.exe is running !if "${INSTALLMODE}" == "currentUser" nsis_tauri_utils::FindProcessCurrentUser "clash-verge-service.exe" !else nsis_tauri_utils::FindProcess "clash-verge-service.exe" !endif Pop $R0 ${If} $R0 = 0 DetailPrint "Kill clash-verge-service.exe..." !if "${INSTALLMODE}" == "currentUser" nsis_tauri_utils::KillProcessCurrentUser "clash-verge-service.exe" !else nsis_tauri_utils::KillProcess "clash-verge-service.exe" !endif ${EndIf} ; Check if clash-meta-alpha.exe is running !if "${INSTALLMODE}" == "currentUser" nsis_tauri_utils::FindProcessCurrentUser "clash-meta-alpha.exe" !else nsis_tauri_utils::FindProcess "clash-meta-alpha.exe" !endif Pop $R0 ${If} $R0 = 0 DetailPrint "Kill clash-meta-alpha.exe..." !if "${INSTALLMODE}" == "currentUser" nsis_tauri_utils::KillProcessCurrentUser "clash-meta-alpha.exe" !else nsis_tauri_utils::KillProcess "clash-meta-alpha.exe" !endif ${EndIf} ; Check if clash-meta.exe is running !if "${INSTALLMODE}" == "currentUser" nsis_tauri_utils::FindProcessCurrentUser "clash-meta.exe" !else nsis_tauri_utils::FindProcess "clash-meta.exe" !endif Pop $R0 ${If} $R0 = 0 DetailPrint "Kill clash-meta.exe..." !if "${INSTALLMODE}" == "currentUser" nsis_tauri_utils::KillProcessCurrentUser "clash-meta.exe" !else nsis_tauri_utils::KillProcess "clash-meta.exe" !endif ${EndIf} !macroend !macro StartVergeService ; Check if the service exists SimpleSC::ExistsService "clash_verge_service" Pop $0 ; 0:service exists;other: service not exists ; Service exists ${If} $0 == 0 Push $0 ; Check if the service is running SimpleSC::ServiceIsRunning "clash_verge_service" Pop $0 ; returns an errorcode (<>0) otherwise success (0) Pop $1 ; returns 1 (service is running) - returns 0 (service is not running) ${If} $0 == 0 Push $0 ${If} $1 == 0 DetailPrint "Restart Clash Verge Service..." SimpleSC::StartService "clash_verge_service" "" 30 ${EndIf} ${ElseIf} $0 != 0 Push $0 SimpleSC::GetErrorMessage Pop $0 MessageBox MB_OK|MB_ICONSTOP "Check Service Status Error ($0)" ${EndIf} ${EndIf} !macroend !macro RemoveVergeService ; Check if the service exists SimpleSC::ExistsService "clash_verge_service" Pop $0 ; 0:service exists;other: service not exists ; Service exists ${If} $0 == 0 Push $0 ; Check if the service is running SimpleSC::ServiceIsRunning "clash_verge_service" Pop $0 ; returns an errorcode (<>0) otherwise success (0) Pop $1 ; returns 1 (service is running) - returns 0 (service is not running) ${If} $0 == 0 Push $0 ${If} $1 == 1 DetailPrint "Stop Clash Verge Service..." SimpleSC::StopService "clash_verge_service" 1 30 Pop $0 ; returns an errorcode (<>0) otherwise success (0) ${If} $0 == 0 DetailPrint "Removing Clash Verge Service..." SimpleSC::RemoveService "clash_verge_service" ${ElseIf} $0 != 0 Push $0 SimpleSC::GetErrorMessage Pop $0 MessageBox MB_OK|MB_ICONSTOP "Clash Verge Service Stop Error ($0)" ${EndIf} ${ElseIf} $1 == 0 DetailPrint "Removing Clash Verge Service..." SimpleSC::RemoveService "clash_verge_service" ${EndIf} ${ElseIf} $0 != 0 Push $0 SimpleSC::GetErrorMessage Pop $0 MessageBox MB_OK|MB_ICONSTOP "Check Service Status Error ($0)" ${EndIf} ${EndIf} !macroend Section EarlyChecks ; Abort silent installer if downgrades is disabled !if "${ALLOWDOWNGRADES}" == "false" IfSilent 0 silent_downgrades_done ; If downgrading ${If} $R0 == -1 System::Call 'kernel32::AttachConsole(i -1)i.r0' ${If} $0 != 0 System::Call 'kernel32::GetStdHandle(i -11)i.r0' System::call 'kernel32::SetConsoleTextAttribute(i r0, i 0x0004)' ; set red color FileWrite $0 "$(silentDowngrades)" ${EndIf} Abort ${EndIf} silent_downgrades_done: !endif SectionEnd Section WebView2 ; Check if Webview2 is already installed and skip this section ${If} ${RunningX64} ReadRegStr $4 HKLM "SOFTWARE\WOW6432Node\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}" "pv" ${Else} ReadRegStr $4 HKLM "SOFTWARE\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}" "pv" ${EndIf} ReadRegStr $5 HKCU "SOFTWARE\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}" "pv" StrCmp $4 "" 0 webview2_done StrCmp $5 "" 0 webview2_done ; Webview2 install modes !if "${INSTALLWEBVIEW2MODE}" == "downloadBootstrapper" Delete "$TEMP\MicrosoftEdgeWebview2Setup.exe" DetailPrint "$(webview2Downloading)" NSISdl::download "https://go.microsoft.com/fwlink/p/?LinkId=2124703" "$TEMP\MicrosoftEdgeWebview2Setup.exe" Pop $0 ${If} $0 == 0 DetailPrint "$(webview2DownloadSuccess)" ${Else} DetailPrint "$(webview2DownloadError)" Abort "$(webview2AbortError)" ${EndIf} StrCpy $6 "$TEMP\MicrosoftEdgeWebview2Setup.exe" Goto install_webview2 !endif !if "${INSTALLWEBVIEW2MODE}" == "embedBootstrapper" Delete "$TEMP\MicrosoftEdgeWebview2Setup.exe" File "/oname=$TEMP\MicrosoftEdgeWebview2Setup.exe" "${WEBVIEW2BOOTSTRAPPERPATH}" DetailPrint "$(installingWebview2)" StrCpy $6 "$TEMP\MicrosoftEdgeWebview2Setup.exe" Goto install_webview2 !endif !if "${INSTALLWEBVIEW2MODE}" == "offlineInstaller" Delete "$TEMP\MicrosoftEdgeWebView2RuntimeInstaller.exe" File "/oname=$TEMP\MicrosoftEdgeWebView2RuntimeInstaller.exe" "${WEBVIEW2INSTALLERPATH}" DetailPrint "$(installingWebview2)" StrCpy $6 "$TEMP\MicrosoftEdgeWebView2RuntimeInstaller.exe" Goto install_webview2 !endif Goto webview2_done install_webview2: DetailPrint "$(installingWebview2)" ; $6 holds the path to the webview2 installer ExecWait "$6 ${WEBVIEW2INSTALLERARGS} /install" $1 ${If} $1 == 0 DetailPrint "$(webview2InstallSuccess)" ${Else} DetailPrint "$(webview2InstallError)" Abort "$(webview2AbortError)" ${EndIf} webview2_done: SectionEnd !macro CheckIfAppIsRunning !if "${INSTALLMODE}" == "currentUser" nsis_tauri_utils::FindProcessCurrentUser "${MAINBINARYNAME}.exe" !else nsis_tauri_utils::FindProcess "${MAINBINARYNAME}.exe" !endif Pop $R0 ${If} $R0 = 0 IfSilent kill 0 ${IfThen} $PassiveMode != 1 ${|} MessageBox MB_OKCANCEL "$(appRunningOkKill)" IDOK kill IDCANCEL cancel ${|} kill: !if "${INSTALLMODE}" == "currentUser" nsis_tauri_utils::KillProcessCurrentUser "${MAINBINARYNAME}.exe" !else nsis_tauri_utils::KillProcess "${MAINBINARYNAME}.exe" !endif Pop $R0 Sleep 500 ${If} $R0 = 0 Goto app_check_done ${Else} IfSilent silent ui silent: System::Call 'kernel32::AttachConsole(i -1)i.r0' ${If} $0 != 0 System::Call 'kernel32::GetStdHandle(i -11)i.r0' System::call 'kernel32::SetConsoleTextAttribute(i r0, i 0x0004)' ; set red color FileWrite $0 "$(appRunning)$\n" ${EndIf} Abort ui: Abort "$(failedToKillApp)" ${EndIf} cancel: Abort "$(appRunning)" ${EndIf} app_check_done: !macroend Section Install SetOutPath $INSTDIR !insertmacro CheckIfAppIsRunning !insertmacro CheckAllVergeProcesses ; Copy main executable File "${MAINBINARYSRCPATH}" ; Copy resources {{#each resources_dirs}} CreateDirectory "$INSTDIR\\{{this}}" {{/each}} {{#each resources}} File /a "/oname={{this.[1]}}" "{{@key}}" {{/each}} ; Copy external binaries {{#each binaries}} File /a "/oname={{this}}" "{{@key}}" {{/each}} !insertmacro StartVergeService ; Create uninstaller WriteUninstaller "$INSTDIR\uninstall.exe" ; Save $INSTDIR in registry for future installations WriteRegStr SHCTX "${MANUPRODUCTKEY}" "" $INSTDIR !if "${INSTALLMODE}" == "both" ; Save install mode to be selected by default for the next installation such as updating ; or when uninstalling WriteRegStr SHCTX "${UNINSTKEY}" $MultiUser.InstallMode 1 !endif ; Registry information for add/remove programs WriteRegStr SHCTX "${UNINSTKEY}" "DisplayName" "${PRODUCTNAME}" WriteRegStr SHCTX "${UNINSTKEY}" "DisplayIcon" "$\"$INSTDIR\${MAINBINARYNAME}.exe$\"" WriteRegStr SHCTX "${UNINSTKEY}" "DisplayVersion" "${VERSION}" WriteRegStr SHCTX "${UNINSTKEY}" "Publisher" "${MANUFACTURER}" WriteRegStr SHCTX "${UNINSTKEY}" "InstallLocation" "$\"$INSTDIR$\"" WriteRegStr SHCTX "${UNINSTKEY}" "UninstallString" "$\"$INSTDIR\uninstall.exe$\"" WriteRegDWORD SHCTX "${UNINSTKEY}" "NoModify" "1" WriteRegDWORD SHCTX "${UNINSTKEY}" "NoRepair" "1" WriteRegDWORD SHCTX "${UNINSTKEY}" "EstimatedSize" "${ESTIMATEDSIZE}" ; Create start menu shortcut (GUI) !insertmacro MUI_STARTMENU_WRITE_BEGIN Application Call CreateStartMenuShortcut !insertmacro MUI_STARTMENU_WRITE_END ; Create shortcuts for silent and passive installers, which ; can be disabled by passing `/NS` flag ; GUI installer has buttons for users to control creating them IfSilent check_ns_flag 0 ${IfThen} $PassiveMode == 1 ${|} Goto check_ns_flag ${|} Goto shortcuts_done check_ns_flag: ${GetOptions} $CMDLINE "/NS" $R0 IfErrors 0 shortcuts_done Call CreateDesktopShortcut Call CreateStartMenuShortcut shortcuts_done: ; Auto close this page for passive mode ${IfThen} $PassiveMode == 1 ${|} SetAutoClose true ${|} SectionEnd Function .onInstSuccess ; Check for `/R` flag only in silent and passive installers because ; GUI installer has a toggle for the user to (re)start the app IfSilent check_r_flag 0 ${IfThen} $PassiveMode == 1 ${|} Goto check_r_flag ${|} Goto run_done check_r_flag: ${GetOptions} $CMDLINE "/R" $R0 IfErrors run_done 0 ${GetOptions} $CMDLINE "/ARGS" $R0 Exec '"$INSTDIR\${MAINBINARYNAME}.exe" $R0' run_done: FunctionEnd Function un.onInit !insertmacro SetContext !if "${INSTALLMODE}" == "both" !insertmacro MULTIUSER_UNINIT !endif !insertmacro MUI_UNGETLANGUAGE FunctionEnd !macro DeleteAppUserModelId !insertmacro ComHlpr_CreateInProcInstance ${CLSID_DestinationList} ${IID_ICustomDestinationList} r1 "" ${If} $1 P<> 0 ${ICustomDestinationList::DeleteList} $1 '("${BUNDLEID}")' ${IUnknown::Release} $1 "" ${EndIf} !insertmacro ComHlpr_CreateInProcInstance ${CLSID_ApplicationDestinations} ${IID_IApplicationDestinations} r1 "" ${If} $1 P<> 0 ${IApplicationDestinations::SetAppID} $1 '("${BUNDLEID}")i.r0' ${If} $0 >= 0 ${IApplicationDestinations::RemoveAllDestinations} $1 '' ${EndIf} ${IUnknown::Release} $1 "" ${EndIf} !macroend ; From https://stackoverflow.com/a/42816728/16993372 !macro UnpinShortcut shortcut !insertmacro ComHlpr_CreateInProcInstance ${CLSID_StartMenuPin} ${IID_IStartMenuPinnedList} r0 "" ${If} $0 P<> 0 System::Call 'SHELL32::SHCreateItemFromParsingName(ws, p0, g "${IID_IShellItem}", *p0r1)' "${shortcut}" ${If} $1 P<> 0 ${IStartMenuPinnedList::RemoveFromList} $0 '(r1)' ${IUnknown::Release} $1 "" ${EndIf} ${IUnknown::Release} $0 "" ${EndIf} !macroend Section Uninstall !insertmacro CheckIfAppIsRunning !insertmacro CheckAllVergeProcesses !insertmacro RemoveVergeService ; Delete the app directory and its content from disk ; Copy main executable Delete "$INSTDIR\${MAINBINARYNAME}.exe" ; Delete resources {{#each resources}} Delete "$INSTDIR\\{{this.[1]}}" {{/each}} Delete "$INSTDIR\resources" ; Delete external binaries {{#each binaries}} Delete "$INSTDIR\\{{this}}" {{/each}} ; Delete uninstaller Delete "$INSTDIR\uninstall.exe" {{#each resources_ancestors}} RMDir /REBOOTOK "$INSTDIR\\{{this}}" {{/each}} RMDir "$INSTDIR" !insertmacro DeleteAppUserModelId !insertmacro UnpinShortcut "$SMPROGRAMS\$AppStartMenuFolder\${MAINBINARYNAME}.lnk" !insertmacro UnpinShortcut "$DESKTOP\${MAINBINARYNAME}.lnk" ; Remove start menu shortcut !insertmacro MUI_STARTMENU_GETFOLDER Application $AppStartMenuFolder Delete "$SMPROGRAMS\$AppStartMenuFolder\${MAINBINARYNAME}.lnk" RMDir "$SMPROGRAMS\$AppStartMenuFolder" ; Remove desktop shortcuts Delete "$DESKTOP\${MAINBINARYNAME}.lnk" ; Remove registry information for add/remove programs !if "${INSTALLMODE}" == "both" DeleteRegKey SHCTX "${UNINSTKEY}" !else if "${INSTALLMODE}" == "perMachine" DeleteRegKey HKLM "${UNINSTKEY}" !else DeleteRegKey HKCU "${UNINSTKEY}" !endif DeleteRegValue HKCU "${MANUPRODUCTKEY}" "Installer Language" ; Delete app data ${If} $DeleteAppDataCheckboxState == 1 SetShellVarContext current RmDir /r "$APPDATA\${BUNDLEID}" RmDir /r "$LOCALAPPDATA\${BUNDLEID}" ${EndIf} ${GetOptions} $CMDLINE "/P" $R0 IfErrors +2 0 SetAutoClose true SectionEnd Function RestorePreviousInstallLocation ReadRegStr $4 SHCTX "${MANUPRODUCTKEY}" "" StrCmp $4 "" +2 0 StrCpy $INSTDIR $4 FunctionEnd Function SkipIfPassive ${IfThen} $PassiveMode == 1 ${|} Abort ${|} FunctionEnd !macro SetLnkAppUserModelId shortcut !insertmacro ComHlpr_CreateInProcInstance ${CLSID_ShellLink} ${IID_IShellLink} r0 "" ${If} $0 P<> 0 ${IUnknown::QueryInterface} $0 '("${IID_IPersistFile}",.r1)' ${If} $1 P<> 0 ${IPersistFile::Load} $1 '("${shortcut}", ${STGM_READWRITE})' ${IUnknown::QueryInterface} $0 '("${IID_IPropertyStore}",.r2)' ${If} $2 P<> 0 System::Call 'Oleaut32::SysAllocString(w "${BUNDLEID}") i.r3' System::Call '*${SYSSTRUCT_PROPERTYKEY}(${PKEY_AppUserModel_ID})p.r4' System::Call '*${SYSSTRUCT_PROPVARIANT}(${VT_BSTR},,&i4 $3)p.r5' ${IPropertyStore::SetValue} $2 '($4,$5)' System::Call 'Oleaut32::SysFreeString($3)' System::Free $4 System::Free $5 ${IPropertyStore::Commit} $2 "" ${IUnknown::Release} $2 "" ${IPersistFile::Save} $1 '("${shortcut}",1)' ${EndIf} ${IUnknown::Release} $1 "" ${EndIf} ${IUnknown::Release} $0 "" ${EndIf} !macroend Function CreateDesktopShortcut CreateShortcut "$DESKTOP\${MAINBINARYNAME}.lnk" "$INSTDIR\${MAINBINARYNAME}.exe" !insertmacro SetLnkAppUserModelId "$DESKTOP\${MAINBINARYNAME}.lnk" FunctionEnd Function CreateStartMenuShortcut CreateDirectory "$SMPROGRAMS\$AppStartMenuFolder" CreateShortcut "$SMPROGRAMS\$AppStartMenuFolder\${MAINBINARYNAME}.lnk" "$INSTDIR\${MAINBINARYNAME}.exe" !insertmacro SetLnkAppUserModelId "$SMPROGRAMS\$AppStartMenuFolder\${MAINBINARYNAME}.lnk" FunctionEnd