Просмотр исходного кода

feat(bundler/NSIS): uninstall previous wix if exist, closes #6859 (#6933)

Amr Bashir 2 лет назад
Родитель
Сommit
60334f9e02

+ 5 - 0
.changes/nsis-uninstall-wix.md

@@ -0,0 +1,5 @@
+---
+'tauri-bundler': 'minor'
+---
+
+NSIS installer will now check if a previous WiX `.msi` installation exist and will prompt users to uninstall it.

+ 91 - 20
tooling/bundler/src/bundle/windows/templates/installer.nsi

@@ -1,6 +1,3 @@
-Var AppStartMenuFolder
-Var ReinstallPageCheck
-
 !include MUI2.nsh
 !include FileFunc.nsh
 !include x64.nsh
@@ -44,11 +41,12 @@ VIAddVersionKey "LegalCopyright" "${COPYRIGHT}"
 VIAddVersionKey "FileVersion" "${VERSION}"
 VIAddVersionKey "ProductVersion" "${VERSION}"
 
+; Plugins path, currently exists for linux only
 !if "${PLUGINSPATH}" != ""
     !addplugindir "${PLUGINSPATH}"
 !endif
 
-
+; Handle install mode, `perUser`, `perMachine` or `both`
 !if "${INSTALLMODE}" == "perMachine"
   RequestExecutionLevel highest
 !endif
@@ -74,14 +72,17 @@ VIAddVersionKey "ProductVersion" "${VERSION}"
   !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}"
@@ -92,26 +93,65 @@ VIAddVersionKey "ProductVersion" "${VERSION}"
 !define MUI_LANGDLL_REGISTRY_KEY "${MANUPRODUCTKEY}"
 !define MUI_LANGDLL_REGISTRY_VALUENAME "Installer Language"
 
-; Installer pages, must be ordered as they appear
+; Installer pages, must be ordered as they should appear to the user
+;
+; 1. Welcome Page
 !insertmacro MUI_PAGE_WELCOME
+
+; 2. License Page (if defined)
 !if "${LICENSE}" != ""
   !insertmacro MUI_PAGE_LICENSE "${LICENSE}"
 !endif
+
+; 3. Install mode (if it is set to `both`)
 !if "${INSTALLMODE}" == "both"
   !insertmacro MULTIUSER_PAGE_INSTALLMODE
 !endif
 
-; Custom page to ask user if he wants to reinstall/uninstall
+
+; 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
+    StrCpy $R5 "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 this installar version with the existing installation
+  ; and modify the messages presented to the user accordingly
+  compare_version:
   StrCpy $R4 "$(older)"
-  ReadRegStr $R0 SHCTX "${UNINSTKEY}" "DisplayVersion"
+  ${If} $R5 == "wix"
+    ReadRegStr $R0 HKLM "$R6" "DisplayVersion"
+  ${Else}
+    ReadRegStr $R0 SHCTX "${UNINSTKEY}" "DisplayVersion"
+  ${EndIf}
   ${IfThen} $R0 == "" ${|} StrCpy $R4 "$(unknown)" ${|}
 
   nsis_tauri_utils::SemverCompare "${VERSION}" $R0
@@ -186,7 +226,6 @@ Function PageReinstallUpdateSelection
   ${Else}
     StrCpy $ReinstallPageCheck 2
   ${EndIf}
-
 FunctionEnd
 Function PageLeaveReinstall
   ${NSD_GetState} $R2 $R1
@@ -197,17 +236,21 @@ Function PageLeaveReinstall
   ;
   ; $R1 holds the radio buttons state. its meaning is dependant on the context
   StrCmp $R0 "1" 0 +2 ; Existing install is not the same version?
-    StrCmp $R1 "1" reinst_uninstall reinst_done
-  StrCmp $R1 "1" reinst_done ; Same version, skip to add/reinstall components?
+    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:
-    ReadRegStr $4 SHCTX "${MANUPRODUCTKEY}" ""
-    ReadRegStr $R1 SHCTX "${UNINSTKEY}" "UninstallString"
-
     HideWindow
-
     ClearErrors
-    ExecWait '$R1 _?=$4' $0
+
+    ${If} $R5 == "wix"
+      ReadRegStr $R1 HKLM "$R6" "UninstallString"
+      ExecWait '$R1' $0
+    ${Else}
+      ReadRegStr $4 SHCTX "${MANUPRODUCTKEY}" ""
+      ReadRegStr $R1 SHCTX "${UNINSTKEY}" "UninstallString"
+      ExecWait '$R1 _?=$4' $0
+    ${EndIf}
 
     BringToFront
 
@@ -232,14 +275,22 @@ Function PageLeaveReinstall
   reinst_done:
 FunctionEnd
 
+; 5. Choose install directoy page
 !insertmacro MUI_PAGE_DIRECTORY
+
+; 6. Start menu shortcut page
+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 to create a desktop shortcut
+; 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
@@ -252,6 +303,7 @@ FunctionEnd
 !insertmacro MUI_PAGE_FINISH
 
 ; Uninstaller Pages
+; 1. Confirm uninstall page
 Var DeleteAppDataCheckbox
 Var DeleteAppDataCheckboxState
 !define /ifndef WS_EX_LAYOUTRTL         0x00400000
@@ -273,6 +325,7 @@ Function un.ConfirmLeave
 FunctionEnd
 !insertmacro MUI_UNPAGE_CONFIRM
 
+; 2. Uninstalling Page
 !insertmacro MUI_UNPAGE_INSTFILES
 
 ;Languages
@@ -295,9 +348,19 @@ Function .onInit
     SetShellVarContext all
   !endif
 
+  ${If} ${RunningX64}
+    !if "${ARCH}" == "x64"
+      SetRegView 64
+    !else if "${ARCH}" == "arm64"
+      SetRegView 64
+    !else
+      SetRegView 32
+    !endif
+  ${EndIf}
+
   ${If} $INSTDIR == ""
+    ; Set default install location
     !if "${INSTALLMODE}" == "perMachine"
-      ; Set default install location
       ${If} ${RunningX64}
         !if "${ARCH}" == "x64"
           StrCpy $INSTDIR "$PROGRAMFILES64\${PRODUCTNAME}"
@@ -349,9 +412,7 @@ Section Webview2
   StrCmp $4 "" 0 done
   StrCmp $5 "" 0 done
 
-  ;--------------------------------
   ; Webview2 install modes
-
   !if "${INSTALLWEBVIEW2MODE}" == "downloadBootstrapper"
     Delete "$TEMP\MicrosoftEdgeWebview2Setup.exe"
     DetailPrint "$(webview2Downloading)"
@@ -494,6 +555,16 @@ Function .onInstSuccess
 FunctionEnd
 
 Function un.onInit
+  ${If} ${RunningX64}
+    !if "${ARCH}" == "x64"
+      SetRegView 64
+    !else if "${ARCH}" == "arm64"
+      SetRegView 64
+    !else
+      SetRegView 32
+    !endif
+  ${EndIf}
+
   !if "${INSTALLMODE}" == "both"
     !insertmacro MULTIUSER_UNINIT
   !endif