Unicode true #### ## Reasonix per-user NSIS installer. ## ## This file is COMMITTED and customized (Wails leaves an existing project.nsi ## untouched and only regenerates wails_tools.nsh). The customizations vs. ## Wails' default template: ## ## 1. REQUEST_EXECUTION_LEVEL "user" + InstallDir under $LOCALAPPDATA - install ## without administrator rights. This is what lets the auto-updater re-run a ## freshly downloaded installer silently (`/S`) with no UAC prompt. ## 2. Uninstall registry under HKCU (not HKLM). Wails' wails.writeUninstaller / ## wails.deleteUninstaller macros hard-code HKLM, which a non-admin install ## cannot write - so we inline HKCU versions below instead. ## 3. InstallDir is remembered across updates via InstallDirRegKey + ## InstallLocation (HKCU\...\Uninstall\InstallLocation). When upgrading from ## a build that did not write InstallLocation yet, .onInit falls back to the ## old DisplayIcon path before using the default. Without this, every release ## forces the user back to %LOCALAPPDATA%\Programs\Reasonix even if they had ## moved the install to a different drive (e.g. D:\Tools\Reasonix); the silent ## auto-updater would re-run with /S into the wrong dir, leaving the old ## install orphaned. ## ## Everything else mirrors Wails' generated default. Defines below override the ## ProjectInfo values that wails_tools.nsh would otherwise populate. #### ## Install per-user (no admin). Must be defined BEFORE including wails_tools.nsh, ## which only sets the "admin" default when REQUEST_EXECUTION_LEVEL is undefined. !define REQUEST_EXECUTION_LEVEL "user" #### ## Include the wails tools (auto-generated; provides INFO_* defines and the ## wails.* macros used below). #### !include "wails_tools.nsh" !include "FileFunc.nsh" !include "LogicLib.nsh" # The version information for this two must consist of 4 parts VIProductVersion "${INFO_PRODUCTVERSION}.0" VIFileVersion "${INFO_PRODUCTVERSION}.0" VIAddVersionKey "CompanyName" "${INFO_COMPANYNAME}" VIAddVersionKey "FileDescription" "${INFO_PRODUCTNAME} Installer" VIAddVersionKey "ProductVersion" "${INFO_PRODUCTVERSION}" VIAddVersionKey "FileVersion" "${INFO_PRODUCTVERSION}" VIAddVersionKey "LegalCopyright" "${INFO_COPYRIGHT}" VIAddVersionKey "ProductName" "${INFO_PRODUCTNAME}" # Enable HiDPI support. https://nsis.sourceforge.io/Reference/ManifestDPIAware ManifestDPIAware true !include "MUI.nsh" !define MUI_ICON "..\icon.ico" !define MUI_UNICON "..\icon.ico" # !define MUI_WELCOMEFINISHPAGE_BITMAP "resources\leftimage.bmp" #Include this to add a bitmap on the left side of the Welcome Page. Must be a size of 164x314 !define MUI_FINISHPAGE_NOAUTOCLOSE # Wait on the INSTFILES page so the user can take a look into the details of the installation steps !define MUI_ABORTWARNING # This will warn the user if they exit from the installer. !insertmacro MUI_PAGE_WELCOME # Welcome to the installer page. # !insertmacro MUI_PAGE_LICENSE "resources\eula.txt" # Adds a EULA page to the installer !insertmacro MUI_PAGE_DIRECTORY # In which folder install page. !insertmacro MUI_PAGE_INSTFILES # Installing page. !insertmacro MUI_PAGE_FINISH # Finished installation page. !insertmacro MUI_UNPAGE_INSTFILES # Uinstalling page !insertmacro MUI_LANGUAGE "English" # Set the Language of the installer ## The following two statements can be used to sign the installer and the uninstaller. The path to the binaries are provided in %1 #!uninstfinalize 'signtool --file "%1"' #!finalize 'signtool --file "%1"' Name "${INFO_PRODUCTNAME}" OutFile "..\..\bin\${INFO_PROJECTNAME}-${ARCH}-installer.exe" # Name of the installer's file. !define REASONIX_DEFAULT_INSTALLDIR "$LOCALAPPDATA\Programs\${INFO_PRODUCTNAME}" !define REASONIX_UPDATE_HELPER "reasonix-update-helper.exe" !define REASONIX_UNLOCK_RETRIES 60 InstallDirRegKey HKCU "${UNINST_KEY}" "InstallLocation" # Reuse the previous install path on update; .onInit falls back to the default on first install. InstallDir "${REASONIX_DEFAULT_INSTALLDIR}" # Per-user install location (no admin rights required). ShowInstDetails show # This will always show the installation details. #### ## Per-user uninstaller registry (HKCU). Replaces wails.writeUninstaller / ## wails.deleteUninstaller, which write HKLM and would fail without admin rights. #### !macro reasonix.writeUninstaller WriteUninstaller "$INSTDIR\uninstall.exe" WriteRegStr HKCU "${UNINST_KEY}" "Publisher" "${INFO_COMPANYNAME}" WriteRegStr HKCU "${UNINST_KEY}" "DisplayName" "${INFO_PRODUCTNAME}" WriteRegStr HKCU "${UNINST_KEY}" "DisplayVersion" "${INFO_PRODUCTVERSION}" WriteRegStr HKCU "${UNINST_KEY}" "DisplayIcon" "$INSTDIR\${PRODUCT_EXECUTABLE}" WriteRegStr HKCU "${UNINST_KEY}" "UninstallString" "$\"$INSTDIR\uninstall.exe$\"" WriteRegStr HKCU "${UNINST_KEY}" "QuietUninstallString" "$\"$INSTDIR\uninstall.exe$\" /S" # Persist the resolved install path so a subsequent update picks it up # via InstallDirRegKey above. Without this, every release would force the # user back to %LOCALAPPDATA%\Programs\Reasonix even if they had moved # the install to a different drive (e.g. D:\Tools\Reasonix). The auto- # updater re-runs this installer with /S and trusts the persisted path, # so it has to be present before the silent re-install. WriteRegStr HKCU "${UNINST_KEY}" "InstallLocation" "$INSTDIR" ${GetSize} "$INSTDIR" "/S=0K" $0 $1 $2 IntFmt $0 "0x%08X" $0 WriteRegDWORD HKCU "${UNINST_KEY}" "EstimatedSize" "$0" !macroend !macro reasonix.deleteUninstaller Delete "$INSTDIR\uninstall.exe" DeleteRegKey HKCU "${UNINST_KEY}" !macroend Function .onInit !insertmacro wails.checkArchitecture ; InstallDirRegKey leaves $INSTDIR empty when the InstallLocation value is ; missing. Older installers still wrote DisplayIcon, so use its parent folder ; as a compatibility bridge before falling back to the per-user default. StrCmp $INSTDIR "" 0 done ClearErrors ReadRegStr $0 HKCU "${UNINST_KEY}" "DisplayIcon" IfErrors fallback StrCmp $0 "" fallback ${GetParent} "$0" $INSTDIR StrCmp $INSTDIR "" fallback done fallback: StrCpy $INSTDIR "${REASONIX_DEFAULT_INSTALLDIR}" done: FunctionEnd Function reasonix.waitForExecutableUnlock IfFileExists "$INSTDIR\${PRODUCT_EXECUTABLE}" 0 done StrCpy $0 0 retry: ClearErrors FileOpen $1 "$INSTDIR\${PRODUCT_EXECUTABLE}" a IfErrors locked FileClose $1 Goto done locked: IntOp $0 $0 + 1 IntCmp $0 ${REASONIX_UNLOCK_RETRIES} failed 0 0 Sleep 1000 Goto retry failed: IfSilent silent interactive interactive: MessageBox MB_RETRYCANCEL|MB_ICONEXCLAMATION "Reasonix is still running. Close Reasonix, then click Retry to continue the installation." IDRETRY retry IDCANCEL abort Goto retry silent: SetErrorLevel 1618 abort: Abort "Reasonix is still running. Close Reasonix and run the installer again." done: FunctionEnd Section !insertmacro wails.setShellContext !insertmacro wails.webview2runtime Call reasonix.waitForExecutableUnlock SetOutPath $INSTDIR !insertmacro wails.files !if /FileExists "${REASONIX_UPDATE_HELPER}" File "/oname=${REASONIX_UPDATE_HELPER}" "${REASONIX_UPDATE_HELPER}" !else !warning "${REASONIX_UPDATE_HELPER} was not found; Windows auto-update will fall back to installer-side waiting only." !endif CreateShortcut "$SMPROGRAMS\${INFO_PRODUCTNAME}.lnk" "$INSTDIR\${PRODUCT_EXECUTABLE}" CreateShortCut "$DESKTOP\${INFO_PRODUCTNAME}.lnk" "$INSTDIR\${PRODUCT_EXECUTABLE}" !insertmacro wails.associateFiles !insertmacro wails.associateCustomProtocols !insertmacro reasonix.writeUninstaller SectionEnd Section "uninstall" !insertmacro wails.setShellContext RMDir /r "$AppData\${PRODUCT_EXECUTABLE}" # Remove the WebView2 DataPath ; Precision uninstall: delete main application files Delete "$INSTDIR\${PRODUCT_EXECUTABLE}" Delete "$INSTDIR\${REASONIX_UPDATE_HELPER}" Delete "$SMPROGRAMS\${INFO_PRODUCTNAME}.lnk" Delete "$DESKTOP\${INFO_PRODUCTNAME}.lnk" !insertmacro wails.unassociateFiles !insertmacro wails.unassociateCustomProtocols !insertmacro reasonix.deleteUninstaller ; Only remove the installation directory if it is empty to prevent data loss RMDir $INSTDIR SectionEnd