Unicode true ManifestDPIAware true ; Add in `dpiAwareness` `PerMonitorV2` to manifest for Windows 10 1607+ (note this should not affect lower versions since they should be able to ignore this and pick up `dpiAware` `true` set by `ManifestDPIAware true`) ; Currently undocumented on NSIS's website but is in the Docs folder of source tree, see ; https://github.com/kichik/nsis/blob/5fc0b87b819a9eec006df4967d08e522ddd651c9/Docs/src/attributes.but#L286-L300 ; https://github.com/tauri-apps/tauri/pull/10106 ManifestDPIAwareness PerMonitorV2 !if "lzma" == "none" SetCompress off !else ; Set the compression algorithm. We default to LZMA. SetCompressor /SOLID "lzma" !endif !include MUI2.nsh !include FileFunc.nsh !include x64.nsh !include WordFunc.nsh !include "utils.nsh" !include "FileAssociation.nsh" !include "Win\COM.nsh" !include "Win\Propkey.nsh" !include "StrFunc.nsh" ${StrCase} ${StrLoc} !define WEBVIEW2APPGUID "{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}" !define MANUFACTURER "ai" !define PRODUCTNAME "jan_productname" !define VERSION "jan_version" !define VERSIONWITHBUILD "jan_build" !define HOMEPAGE "" !define INSTALLMODE "currentUser" !define LICENSE "" !define INSTALLERICON "D:\a\jan\jan\src-tauri\icons\icon.ico" !define SIDEBARIMAGE "" !define HEADERIMAGE "" !define MAINBINARYNAME "jan_mainbinaryname" !define MAINBINARYSRCPATH "D:\a\jan\jan\src-tauri\target\release\jan_mainbinaryname.exe" !define BUNDLEID "jan_mainbinaryname.ai.app" !define COPYRIGHT "" !define OUTFILE "nsis-output.exe" !define ARCH "x64" !define ADDITIONALPLUGINSPATH "D:\a\jan\jan\src-tauri\target\release\nsis\x64\Plugins\x86-unicode\additional" !define ALLOWDOWNGRADES "true" !define DISPLAYLANGUAGESELECTOR "false" !define INSTALLWEBVIEW2MODE "downloadBootstrapper" !define WEBVIEW2INSTALLERARGS "/silent" !define WEBVIEW2BOOTSTRAPPERPATH "" !define WEBVIEW2INSTALLERPATH "" !define MINIMUMWEBVIEW2VERSION "" !define UNINSTKEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCTNAME}" !define MANUKEY "Software\${MANUFACTURER}" !define MANUPRODUCTKEY "${MANUKEY}\${PRODUCTNAME}" !define UNINSTALLERSIGNCOMMAND "$\"powershell$\" $\"-ExecutionPolicy$\" $\"Bypass$\" $\"-File$\" $\"./sign.ps1$\" $\"%1$\"" !define ESTIMATEDSIZE "793795" !define STARTMENUFOLDER "" !define VCREDIST_URL "https://aka.ms/vs/17/release/vc_redist.x64.exe" !define VCREDIST_FILENAME "vc_redist.x64.exe" Var PassiveMode Var UpdateMode Var NoShortcutMode Var WixMode Var OldMainBinaryName Name "${PRODUCTNAME}" BrandingText "${COPYRIGHT}" OutFile "${OUTFILE}" ShowInstDetails nevershow ShowUninstDetails nevershow ; We don't actually use this value as default install path, ; it's just for nsis to append the product name folder in the directory selector ; https://nsis.sourceforge.io/Reference/InstallDir !define PLACEHOLDER_INSTALL_DIR "placeholder\${PRODUCTNAME}" InstallDir "${PLACEHOLDER_INSTALL_DIR}" VIProductVersion "${VERSIONWITHBUILD}" VIAddVersionKey "ProductName" "${PRODUCTNAME}" VIAddVersionKey "FileDescription" "${PRODUCTNAME}" VIAddVersionKey "LegalCopyright" "${COPYRIGHT}" VIAddVersionKey "FileVersion" "${VERSION}" VIAddVersionKey "ProductVersion" "${VERSION}" # additional plugins !addplugindir "${ADDITIONALPLUGINSPATH}" ; Uninstaller signing command !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 installation was detected Var ReinstallPageCheck Page custom PageReinstall PageLeaveReinstall Function PageReinstall ; Uninstall previous WiX installation if exists. ; ; A WiX installer stores the installation 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 potential 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_loop_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_loop_done StrCpy $WixMode 1 StrCpy $R6 "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$1" Goto compare_version wix_loop_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} $WixMode = 1 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)" ; Upgrading ${ElseIf} $R0 = 1 StrCpy $R1 "$(olderOrUnknownVersionInstalled)" StrCpy $R2 "$(uninstallBeforeInstalling)" StrCpy $R3 "$(dontUninstall)" !insertmacro MUI_HEADER_TEXT "$(alreadyInstalled)" "$(choowHowToInstall)" ; 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)" ${Else} Abort ${EndIf} ; Skip showing the page if passive ; ; Note that we don't call this earlier at the begining ; of this function because we need to populate some variables ; related to current installed version if detected and whether ; we are downgrading or not. ${If} $PassiveMode = 1 Call PageLeaveReinstall ${Else} 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 ${EndIf} FunctionEnd Function PageReinstallUpdateSelection ${NSD_GetState} $R2 $R1 ${If} $R1 == ${BST_CHECKED} StrCpy $ReinstallPageCheck 1 ${Else} StrCpy $ReinstallPageCheck 2 ${EndIf} FunctionEnd Function PageLeaveReinstall ; In passive mode, always uninstall when upgrading ${If} $PassiveMode = 1 ${AndIf} $R0 = 1 ; Upgrading Goto reinst_uninstall ${EndIf} ${NSD_GetState} $R2 $R1 ; If migrating from Wix, always uninstall ${If} $WixMode = 1 Goto reinst_uninstall ${EndIf} ; In update mode, always proceeds without uninstalling ${If} $UpdateMode = 1 Goto reinst_done ${EndIf} ; $R0 holds whether same(0)/upgrading(1)/downgrading(-1) version ; $R1 holds the radio buttons state: ; 1 => first choice was selected ; 0 => second choice was selected ${If} $R0 = 0 ; Same version, proceed ${If} $R1 = 1 ; User chose to add/reinstall Goto reinst_done ${Else} ; User chose to uninstall Goto reinst_uninstall ${EndIf} ${ElseIf} $R0 = 1 ; Upgrading ${If} $R1 = 1 ; User chose to uninstall Goto reinst_uninstall ${Else} Goto reinst_done ; User chose NOT to uninstall ${EndIf} ${ElseIf} $R0 = -1 ; Downgrading ${If} $R1 = 1 ; User chose to uninstall Goto reinst_uninstall ${Else} Goto reinst_done ; User chose NOT to uninstall ${EndIf} ${EndIf} reinst_uninstall: HideWindow ClearErrors ${If} $WixMode = 1 ReadRegStr $R1 HKLM "$R6" "UninstallString" ExecWait '$R1' $0 ${Else} ReadRegStr $4 SHCTX "${MANUPRODUCTKEY}" "" ReadRegStr $R1 SHCTX "${UNINSTKEY}" "UninstallString" ${IfThen} $UpdateMode = 1 ${|} StrCpy $R1 "$R1 /UPDATE" ${|} ; append /UPDATE ${IfThen} $PassiveMode = 1 ${|} StrCpy $R1 "$R1 /P" ${|} ; append /P StrCpy $R1 "$R1 _?=$4" ; append uninstall directory ExecWait '$R1' $0 ${EndIf} BringToFront ${IfThen} ${Errors} ${|} StrCpy $0 2 ${|} ; ExecWait failed, set fake exit code ${If} $0 <> 0 ${OrIf} ${FileExists} "$INSTDIR\${MAINBINARYNAME}.exe" ; User cancelled wix uninstaller? return to select un/reinstall page ${If} $WixMode = 1 ${AndIf} $0 = 1602 Abort ${EndIf} ; User cancelled NSIS uninstaller? return to select un/reinstall page ${If} $0 = 1 Abort ${EndIf} ; Other erros? show generic error message and return to select un/reinstall page MessageBox MB_ICONEXCLAMATION "$(unableToUninstall)" Abort ${EndIf} reinst_done: FunctionEnd ; 5. Choose install directory page !define MUI_PAGE_CUSTOMFUNCTION_PRE SkipIfPassive !insertmacro MUI_PAGE_DIRECTORY ; 6. Start menu shortcut page Var AppStartMenuFolder !if "${STARTMENUFOLDER}" != "" !define MUI_PAGE_CUSTOMFUNCTION_PRE SkipIfPassive !define MUI_STARTMENUPAGE_DEFAULTFOLDER "${STARTMENUFOLDER}" !else !define MUI_PAGE_CUSTOMFUNCTION_PRE Skip !endif !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 CreateOrUpdateDesktopShortcut ; Show run app after installation. !define MUI_FINISHPAGE_RUN !define MUI_FINISHPAGE_RUN_FUNCTION RunMainBinary !define MUI_PAGE_CUSTOMFUNCTION_PRE SkipIfPassive !insertmacro MUI_PAGE_FINISH Function RunMainBinary nsis_tauri_utils::RunAsUser "$INSTDIR\${MAINBINARYNAME}.exe" "" FunctionEnd ; 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 ; Add add a `Delete app data` check box ; $1 inner dialog HWND ; $2 window DPI ; $3 style ; $4 x ; $5 y ; $6 width ; $7 height FindWindow $1 "#32770" "" $HWNDPARENT ; Find inner dialog System::Call "user32::GetDpiForWindow(p r1) i .r2" ${If} $(^RTL) = 1 StrCpy $3 "${__NSD_CheckBox_EXSTYLE} | ${WS_EX_LAYOUTRTL}" IntOp $4 50 * $2 ${Else} StrCpy $3 "${__NSD_CheckBox_EXSTYLE}" IntOp $4 0 * $2 ${EndIf} IntOp $5 100 * $2 IntOp $6 400 * $2 IntOp $7 25 * $2 IntOp $4 $4 / 96 IntOp $5 $5 / 96 IntOp $6 $6 / 96 IntOp $7 $7 / 96 System::Call 'user32::CreateWindowEx(i r3, w "${__NSD_CheckBox_CLASS}", w "$(deleteAppData)", i ${__NSD_CheckBox_STYLE}, i r4, i r5, i r6, i r7, p r1, i0, i0, i0) i .s' 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 !define MUI_PAGE_CUSTOMFUNCTION_PRE un.SkipIfPassive !insertmacro MUI_UNPAGE_CONFIRM ; 2. Uninstalling Page !insertmacro MUI_UNPAGE_INSTFILES ;Languages !insertmacro MUI_LANGUAGE "English" !insertmacro MUI_RESERVEFILE_LANGDLL !include "D:\a\jan\jan\src-tauri\target\release\nsis\x64\English.nsh" Function .onInit ${GetOptions} $CMDLINE "/P" $PassiveMode ${IfNot} ${Errors} StrCpy $PassiveMode 1 ${EndIf} ; always run in passive mode StrCpy $PassiveMode 1 ${GetOptions} $CMDLINE "/NS" $NoShortcutMode ${IfNot} ${Errors} StrCpy $NoShortcutMode 1 ${EndIf} ${GetOptions} $CMDLINE "/UPDATE" $UpdateMode ${IfNot} ${Errors} StrCpy $UpdateMode 1 ${EndIf} !if "${DISPLAYLANGUAGESELECTOR}" == "true" !insertmacro MUI_LANGDLL_DISPLAY !endif !insertmacro SetContext ${If} $INSTDIR == "${PLACEHOLDER_INSTALL_DIR}" ; 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\Programs\${PRODUCTNAME}" !endif Call RestorePreviousInstallLocation ${EndIf} ; Remove old Jan if it exists ${If} ${FileExists} "$INSTDIR\LICENSE.electron.txt" DeleteRegKey HKLM "Software\${PRODUCTNAME}" RMDir /r "$INSTDIR" Delete "$INSTDIR\*.*" ${EndIf} !if "${INSTALLMODE}" == "both" !insertmacro MULTIUSER_INIT !endif FunctionEnd Section EarlyChecks ; Abort silent installer if downgrades is disabled !if "${ALLOWDOWNGRADES}" == "false" ${If} ${Silent} ; 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} ${EndIf} !endif SectionEnd Section WebView2 ; Check if Webview2 is already installed and skip this section ${If} ${RunningX64} ReadRegStr $4 HKLM "SOFTWARE\WOW6432Node\Microsoft\EdgeUpdate\Clients\${WEBVIEW2APPGUID}" "pv" ${Else} ReadRegStr $4 HKLM "SOFTWARE\Microsoft\EdgeUpdate\Clients\${WEBVIEW2APPGUID}" "pv" ${EndIf} ${If} $4 == "" ReadRegStr $4 HKCU "SOFTWARE\Microsoft\EdgeUpdate\Clients\${WEBVIEW2APPGUID}" "pv" ${EndIf} ${If} $4 == "" ; Webview2 installation ; ; Skip if updating ${If} $UpdateMode <> 1 !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 == "success" 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: ${EndIf} ${Else} !if "${MINIMUMWEBVIEW2VERSION}" != "" ${VersionCompare} "${MINIMUMWEBVIEW2VERSION}" "$4" $R0 ${If} $R0 = 1 update_webview: DetailPrint "$(installingWebview2)" ${If} ${RunningX64} ReadRegStr $R1 HKLM "SOFTWARE\WOW6432Node\Microsoft\EdgeUpdate" "path" ${Else} ReadRegStr $R1 HKLM "SOFTWARE\Microsoft\EdgeUpdate" "path" ${EndIf} ${If} $R1 == "" ReadRegStr $R1 HKCU "SOFTWARE\Microsoft\EdgeUpdate" "path" ${EndIf} ${If} $R1 != "" ; Chromium updater docs: https://source.chromium.org/chromium/chromium/src/+/main:docs/updater/user_manual.md ; Modified from "HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\Microsoft EdgeWebView\ModifyPath" ExecWait `"$R1" /install appguid=${WEBVIEW2APPGUID}&needsadmin=true` $1 ${If} $1 = 0 DetailPrint "$(webview2InstallSuccess)" ${Else} MessageBox MB_ICONEXCLAMATION|MB_ABORTRETRYIGNORE "$(webview2InstallError)" IDIGNORE ignore IDRETRY update_webview Quit ignore: ${EndIf} ${EndIf} ${EndIf} !endif ${EndIf} SectionEnd Section VCRedist ; Check if VC++ Redistributable is already installed ; Check for Visual Studio 2015-2022 redistributable (14.0 or higher) ReadRegStr $0 HKLM "SOFTWARE\Microsoft\VisualStudio\14.0\VC\Runtimes\x64" "Version" ${If} $0 == "" ; Try alternative registry location ReadRegStr $0 HKLM "SOFTWARE\WOW6432Node\Microsoft\VisualStudio\14.0\VC\Runtimes\x64" "Version" ${EndIf} ${If} $0 == "" ; Try checking for any version of Visual C++ 2015-2022 Redistributable ReadRegStr $0 HKLM "SOFTWARE\Classes\Installer\Dependencies\Microsoft.VS.VC_RuntimeMinimumVSU_amd64,v14" "Version" ${EndIf} ${If} $0 == "" ; VC++ Redistributable not found, need to install DetailPrint "Visual C++ Redistributable not found, downloading and installing..." ; Download VC++ Redistributable Delete "$TEMP\${VCREDIST_FILENAME}" DetailPrint "Downloading Visual C++ Redistributable..." NSISdl::download "${VCREDIST_URL}" "$TEMP\${VCREDIST_FILENAME}" Pop $1 ${If} $1 == "success" DetailPrint "Visual C++ Redistributable download successful" ; Install VC++ Redistributable silently DetailPrint "Installing Visual C++ Redistributable..." ExecWait '"$TEMP\${VCREDIST_FILENAME}" /quiet /norestart' $2 ${If} $2 == 0 DetailPrint "Visual C++ Redistributable installed successfully" ${ElseIf} $2 == 1638 DetailPrint "Visual C++ Redistributable already installed (newer version)" ${ElseIf} $2 == 3010 DetailPrint "Visual C++ Redistributable installed successfully (restart required)" ; You might want to handle restart requirement here ${Else} DetailPrint "Visual C++ Redistributable installation failed with exit code: $2" MessageBox MB_ICONEXCLAMATION|MB_YESNO "Visual C++ Redistributable installation failed. Continue anyway?" IDYES continue_install Abort "Installation cancelled due to Visual C++ Redistributable failure" continue_install: ${EndIf} ; Clean up downloaded file Delete "$TEMP\${VCREDIST_FILENAME}" ${Else} DetailPrint "Failed to download Visual C++ Redistributable: $1" MessageBox MB_ICONEXCLAMATION|MB_YESNO "Failed to download Visual C++ Redistributable. Continue anyway?" IDYES continue_install_download_fail Abort "Installation cancelled due to download failure" continue_install_download_fail: ${EndIf} ${Else} DetailPrint "Visual C++ Redistributable already installed (version: $0)" ${EndIf} SectionEnd Section Install SetDetailsPrint none SetOutPath $INSTDIR !ifmacrodef NSIS_HOOK_PREINSTALL !insertmacro NSIS_HOOK_PREINSTALL !endif !insertmacro CheckIfAppIsRunning "${MAINBINARYNAME}.exe" "${PRODUCTNAME}" ; Copy main executable File "${MAINBINARYSRCPATH}" ; Copy resources CreateDirectory "$INSTDIR\resources" CreateDirectory "$INSTDIR\resources\pre-install" SetOutPath $INSTDIR File /a "/oname=vulkan-1.dll" "D:\a\jan\jan\src-tauri\resources\lib\vulkan-1.dll" File /a "/oname=LICENSE" "D:\a\jan\jan\src-tauri\resources\LICENSE" SetOutPath "$INSTDIR\resources\pre-install" File /nonfatal /a /r "D:\a\jan\jan\src-tauri\resources\pre-install\" SetOutPath $INSTDIR ; Copy external binaries File /a "/oname=bun.exe" "D:\a\jan\jan\src-tauri\resources\bin\bun-x86_64-pc-windows-msvc.exe" File /a "/oname=uv.exe" "D:\a\jan\jan\src-tauri\resources\bin\uv-x86_64-pc-windows-msvc.exe" ; Create file associations ; Register deep links ; 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 ; Remove old main binary if it doesn't match new main binary name ReadRegStr $OldMainBinaryName SHCTX "${UNINSTKEY}" "MainBinaryName" ${If} $OldMainBinaryName != "" ${AndIf} $OldMainBinaryName != "${MAINBINARYNAME}.exe" Delete "$INSTDIR\$OldMainBinaryName" ${EndIf} ; Save current MAINBINARYNAME for future updates WriteRegStr SHCTX "${UNINSTKEY}" "MainBinaryName" "${MAINBINARYNAME}.exe" ; 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" ${GetSize} "$INSTDIR" "/M=uninstall.exe /S=0K /G=0" $0 $1 $2 IntOp $0 $0 + ${ESTIMATEDSIZE} IntFmt $0 "0x%08X" $0 WriteRegDWORD SHCTX "${UNINSTKEY}" "EstimatedSize" "$0" !if "${HOMEPAGE}" != "" WriteRegStr SHCTX "${UNINSTKEY}" "URLInfoAbout" "${HOMEPAGE}" WriteRegStr SHCTX "${UNINSTKEY}" "URLUpdateInfo" "${HOMEPAGE}" WriteRegStr SHCTX "${UNINSTKEY}" "HelpLink" "${HOMEPAGE}" !endif ; Create start menu shortcut !insertmacro MUI_STARTMENU_WRITE_BEGIN Application Call CreateOrUpdateStartMenuShortcut !insertmacro MUI_STARTMENU_WRITE_END ; Create desktop shortcut for silent and passive installers ; because finish page will be skipped ${If} $PassiveMode = 1 ${OrIf} ${Silent} Call CreateOrUpdateDesktopShortcut ${EndIf} !ifmacrodef NSIS_HOOK_POSTINSTALL !insertmacro NSIS_HOOK_POSTINSTALL !endif ; Auto close this page for passive mode ${If} $PassiveMode = 1 SetAutoClose true ${EndIf} 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 ${If} $PassiveMode = 1 ${OrIf} ${Silent} ; ${GetOptions} $CMDLINE "/R" $R0 ; ${IfNot} ${Errors} ${GetOptions} $CMDLINE "/ARGS" $R0 nsis_tauri_utils::RunAsUser "$INSTDIR\${MAINBINARYNAME}.exe" "$R0" ; ${EndIf} ${EndIf} FunctionEnd Function un.onInit !insertmacro SetContext !if "${INSTALLMODE}" == "both" !insertmacro MULTIUSER_UNINIT !endif !insertmacro MUI_UNGETLANGUAGE ${GetOptions} $CMDLINE "/P" $PassiveMode ${IfNot} ${Errors} StrCpy $PassiveMode 1 ${EndIf} ${GetOptions} $CMDLINE "/UPDATE" $UpdateMode ${IfNot} ${Errors} StrCpy $UpdateMode 1 ${EndIf} FunctionEnd Section Uninstall SetDetailsPrint none !ifmacrodef NSIS_HOOK_PREUNINSTALL !insertmacro NSIS_HOOK_PREUNINSTALL !endif !insertmacro CheckIfAppIsRunning "${MAINBINARYNAME}.exe" "${PRODUCTNAME}" ; Delete the app directory and its content from disk ; Copy main executable Delete "$INSTDIR\${MAINBINARYNAME}.exe" ; Delete LICENSE file Delete "$INSTDIR\LICENSE" ; Delete resources Delete "$INSTDIR\resources\pre-install\janhq-assistant-extension-1.0.2.tgz" Delete "$INSTDIR\resources\pre-install\janhq-conversational-extension-1.0.0.tgz" Delete "$INSTDIR\resources\pre-install\janhq-engine-management-extension-1.0.3.tgz" Delete "$INSTDIR\resources\pre-install\janhq-hardware-management-extension-1.0.0.tgz" Delete "$INSTDIR\resources\pre-install\janhq-inference-cortex-extension-1.0.25.tgz" Delete "$INSTDIR\resources\pre-install\janhq-model-extension-1.0.36.tgz" ; Delete external binaries Delete "$INSTDIR\bun.exe" Delete "$INSTDIR\uv.exe" ; Delete app associations ; Delete deep links ; Delete uninstaller Delete "$INSTDIR\uninstall.exe" RMDir /REBOOTOK "$INSTDIR\resources\pre-install" RMDir /r /REBOOTOK "$INSTDIR\resources" RMDir /r "$INSTDIR" ; Remove shortcuts if not updating ${If} $UpdateMode <> 1 !insertmacro DeleteAppUserModelId ; Remove start menu shortcut !insertmacro MUI_STARTMENU_GETFOLDER Application $AppStartMenuFolder !insertmacro IsShortcutTarget "$SMPROGRAMS\$AppStartMenuFolder\${PRODUCTNAME}.lnk" "$INSTDIR\${MAINBINARYNAME}.exe" Pop $0 ${If} $0 = 1 !insertmacro UnpinShortcut "$SMPROGRAMS\$AppStartMenuFolder\${PRODUCTNAME}.lnk" Delete "$SMPROGRAMS\$AppStartMenuFolder\${PRODUCTNAME}.lnk" RMDir "$SMPROGRAMS\$AppStartMenuFolder" ${EndIf} !insertmacro IsShortcutTarget "$SMPROGRAMS\${PRODUCTNAME}.lnk" "$INSTDIR\${MAINBINARYNAME}.exe" Pop $0 ${If} $0 = 1 !insertmacro UnpinShortcut "$SMPROGRAMS\${PRODUCTNAME}.lnk" Delete "$SMPROGRAMS\${PRODUCTNAME}.lnk" ${EndIf} ; Remove desktop shortcuts !insertmacro IsShortcutTarget "$DESKTOP\${PRODUCTNAME}.lnk" "$INSTDIR\${MAINBINARYNAME}.exe" Pop $0 ${If} $0 = 1 !insertmacro UnpinShortcut "$DESKTOP\${PRODUCTNAME}.lnk" Delete "$DESKTOP\${PRODUCTNAME}.lnk" ${EndIf} ${EndIf} ; 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 ; Removes the Autostart entry for ${PRODUCTNAME} from the HKCU Run key if it exists. ; This ensures the program does not launch automatically after uninstallation if it exists. ; If it doesn't exist, it does nothing. ; We do this when not updating (to preserve the registry value on updates) ${If} $UpdateMode <> 1 DeleteRegValue HKCU "Software\Microsoft\Windows\CurrentVersion\Run" "${PRODUCTNAME}" ${EndIf} ; Delete app data if the checkbox is selected ; and if not updating ${If} $DeleteAppDataCheckboxState = 1 ${AndIf} $UpdateMode <> 1 ; Clear the install location $INSTDIR from registry DeleteRegKey SHCTX "${MANUPRODUCTKEY}" DeleteRegKey /ifempty SHCTX "${MANUKEY}" ; Clear the install language from registry DeleteRegValue HKCU "${MANUPRODUCTKEY}" "Installer Language" DeleteRegKey /ifempty HKCU "${MANUPRODUCTKEY}" DeleteRegKey /ifempty HKCU "${MANUKEY}" SetShellVarContext current RmDir /r "$APPDATA\${BUNDLEID}" RmDir /r "$LOCALAPPDATA\${BUNDLEID}" ${EndIf} !ifmacrodef NSIS_HOOK_POSTUNINSTALL !insertmacro NSIS_HOOK_POSTUNINSTALL !endif ; Auto close if passive mode or updating ${If} $PassiveMode = 1 ${OrIf} $UpdateMode = 1 SetAutoClose true ${EndIf} SectionEnd Function RestorePreviousInstallLocation ReadRegStr $4 SHCTX "${MANUPRODUCTKEY}" "" StrCmp $4 "" +2 0 StrCpy $INSTDIR $4 FunctionEnd Function Skip Abort FunctionEnd Function SkipIfPassive ${IfThen} $PassiveMode = 1 ${|} Abort ${|} FunctionEnd Function un.SkipIfPassive ${IfThen} $PassiveMode = 1 ${|} Abort ${|} FunctionEnd Function CreateOrUpdateStartMenuShortcut ; We used to use product name as MAINBINARYNAME ; migrate old shortcuts to target the new MAINBINARYNAME StrCpy $R0 0 !insertmacro IsShortcutTarget "$SMPROGRAMS\$AppStartMenuFolder\${PRODUCTNAME}.lnk" "$INSTDIR\$OldMainBinaryName" Pop $0 ${If} $0 = 1 !insertmacro SetShortcutTarget "$SMPROGRAMS\$AppStartMenuFolder\${PRODUCTNAME}.lnk" "$INSTDIR\${MAINBINARYNAME}.exe" StrCpy $R0 1 ${EndIf} !insertmacro IsShortcutTarget "$SMPROGRAMS\${PRODUCTNAME}.lnk" "$INSTDIR\$OldMainBinaryName" Pop $0 ${If} $0 = 1 !insertmacro SetShortcutTarget "$SMPROGRAMS\${PRODUCTNAME}.lnk" "$INSTDIR\${MAINBINARYNAME}.exe" StrCpy $R0 1 ${EndIf} ${If} $R0 = 1 Return ${EndIf} ; Skip creating shortcut if in update mode or no shortcut mode ; but always create if migrating from wix ${If} $WixMode = 0 ${If} $UpdateMode = 1 ${OrIf} $NoShortcutMode = 1 Return ${EndIf} ${EndIf} !if "${STARTMENUFOLDER}" != "" CreateDirectory "$SMPROGRAMS\$AppStartMenuFolder" CreateShortcut "$SMPROGRAMS\$AppStartMenuFolder\${PRODUCTNAME}.lnk" "$INSTDIR\${MAINBINARYNAME}.exe" !insertmacro SetLnkAppUserModelId "$SMPROGRAMS\$AppStartMenuFolder\${PRODUCTNAME}.lnk" !else CreateShortcut "$SMPROGRAMS\${PRODUCTNAME}.lnk" "$INSTDIR\${MAINBINARYNAME}.exe" !insertmacro SetLnkAppUserModelId "$SMPROGRAMS\${PRODUCTNAME}.lnk" !endif FunctionEnd Function CreateOrUpdateDesktopShortcut ; We used to use product name as MAINBINARYNAME ; migrate old shortcuts to target the new MAINBINARYNAME !insertmacro IsShortcutTarget "$DESKTOP\${PRODUCTNAME}.lnk" "$INSTDIR\$OldMainBinaryName" Pop $0 ${If} $0 = 1 !insertmacro SetShortcutTarget "$DESKTOP\${PRODUCTNAME}.lnk" "$INSTDIR\${MAINBINARYNAME}.exe" Return ${EndIf} ; Skip creating shortcut if in update mode or no shortcut mode ; but always create if migrating from wix ${If} $WixMode = 0 ${If} $UpdateMode = 1 ${OrIf} $NoShortcutMode = 1 Return ${EndIf} ${EndIf} CreateShortcut "$DESKTOP\${PRODUCTNAME}.lnk" "$INSTDIR\${MAINBINARYNAME}.exe" !insertmacro SetLnkAppUserModelId "$DESKTOP\${PRODUCTNAME}.lnk" FunctionEnd