jan/src-tauri/tauri.bundle.windows.nsis.template
2025-08-26 11:17:59 +07:00

1007 lines
33 KiB
Plaintext

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