Fix windows uninstaller issue #10971 and #11232 (#11268)

* Move MultiUser install mode default registry key to the uninstaller registry entry

Lets the uninstaller detect the correct context for each installed version. related to #10971

* Fix uninstaller doesn't use correct shell context when installed for current user

related to #10971

* Update installer init checks for previously installed versions

Use shell context determined by the MultiUser plugin. related to #10971

* fix: Perform installer version checks after install mode selection

Perform installer version checks after install mode selection to ensure that they are done for the correct reg root key. Fixes #10971.

* Call version check method also in silent mode

* Add TrimQuotes macro to installer utilities

Also remove FileCheck macro

* Update comment in gui.nsh

* Change Windows installer/uninstaller FileDescription entry

related to #11232
This commit is contained in:
alexbeer2048
2023-11-14 03:48:13 +01:00
committed by GitHub
parent 4ff00ef998
commit 6373760845
5 changed files with 91 additions and 98 deletions

View File

@@ -23,8 +23,8 @@ ManifestDPIAware true
# Multi-User settings
!define MULTIUSER_EXECUTIONLEVEL Highest
!define MULTIUSER_INSTALLMODE_COMMANDLINE
!define MULTIUSER_INSTALLMODE_DEFAULT_REGISTRY_KEY "${APP_REGKEY}"
!define MULTIUSER_INSTALLMODE_DEFAULT_REGISTRY_VALUENAME ""
!define MULTIUSER_INSTALLMODE_DEFAULT_REGISTRY_KEY "${APP_UNINST_KEY}"
!define MULTIUSER_INSTALLMODE_DEFAULT_REGISTRY_VALUENAME "DisplayVersion"
!define MULTIUSER_INSTALLMODE_INSTDIR "${APP_DIR}"
!define MULTIUSER_INSTALLMODE_INSTDIR_REGISTRY_KEY "${APP_REGKEY}"

View File

@@ -25,7 +25,7 @@ Configuration and variables of FreeCAD installer
# Fixme: FC should use different preferences folder for every release
!define APP_DIR_USERDATA ${APP_NAME}
#!define APP_DIR_USERDATA "${APP_NAME}${APP_VERSION_MAJOR}.${APP_VERSION_MINOR}"
!define APP_INFO "${APP_NAME} - Your Own 3D Parametric Modeler"
!define APP_INFO "${APP_NAME} Installer/Uninstaller"
!define APP_WEBPAGE "https://www.freecad.org/"
!define APP_WEBPAGE_INFO "${APP_NAME} Website"
!define APP_WIKI "https://wiki.freecad.org/Main_Page"

View File

@@ -37,7 +37,10 @@ BrandingText " "
!define MUI_LICENSEPAGE_TEXT_BOTTOM " "
!insertmacro MUI_PAGE_LICENSE "${FILES_LICENSE}"
# Decision if it should be installed as admin or not
# Select install mode
# set custom function for additional checks after the user selected the install mode
# note: will not be called in silent mode
!define MULTIUSER_PAGE_CUSTOMFUNCTION_LEAVE PostMultiUserPageInit
!insertmacro MULTIUSER_PAGE_INSTALLMODE
# Specify the installation directory.

View File

@@ -21,6 +21,63 @@ Function InitUser
FunctionEnd
#--------------------------------
# MultiUser custom method
Function PostMultiUserPageInit
# check if this FreeCAD version is already installed
ReadRegStr $0 SHCTX "${APP_UNINST_KEY}" "UninstallString"
${if} $0 != ""
# check if the uninstaller was acidentally deleted
# if so, don't bother the user if they really want to install a new FreeCAD over an existing one
# because they won't have a chance to deny this
# remove quotes from uninstaller filename
${TrimQuotes} $0 $0
# skip message box if uninstaller file is missing
IfFileExists $0 0 ContinueInstall
# installing over an existing installation of the same FreeCAD release is not necessary
# if the users does this, they most probably have a problem with FreeCAD that can better be solved
# by reinstalling FreeCAD
# for beta and other test releases over-installing can even cause errors
MessageBox MB_YESNOCANCEL "$(AlreadyInstalled)" /SD IDCANCEL IDYES ContinueInstall IDNO BackToMuiltUserPage
Quit
BackToMuiltUserPage:
Abort
ContinueInstall:
${endif}
# check if there is an existing FreeCAD installation of the same FreeCAD series
# we usually don't release more than 10 versions so with 20 we are safe to check if a newer version is installed
IntOp $4 ${APP_VERSION_REVISION} + 20
${for} $5 0 $4
ReadRegStr $0 SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APP_NAME}${APP_VERSION_MAJOR}${APP_VERSION_MINOR}$5" "DisplayVersion"
# also check for an emergency release
${if} $0 == ""
ReadRegStr $0 SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APP_NAME}${APP_VERSION_MAJOR}${APP_VERSION_MINOR}$51" "DisplayVersion"
${endif}
${if} $0 != ""
StrCpy $R5 $0 # store the read version number
StrCpy $OldVersionNumber "${APP_VERSION_MAJOR}${APP_VERSION_MINOR}$5"
# we don't stop here because we want the latest installed version
${endif}
${next}
# NSIS cannot handle numbers with leading zero, thus cut it off before comparing
StrCpy $1 $OldVersionNumber "" 1
StrCpy $2 ${APP_SERIES_KEY} "" 1
${if} $1 > $2
# store the version number and reformat it temporarily for the error message
StrCpy $R0 $OldVersionNumber
StrCpy $OldVersionNumber $R5
MessageBox MB_OK|MB_ICONSTOP "$(NewerInstalled)" /SD IDOK
StrCpy $OldVersionNumber $R0
Quit
${endif}
FunctionEnd
#--------------------------------
# visible installer sections
@@ -75,73 +132,6 @@ Function .onInit
# initialize the multi-uder installer UI
!insertmacro MULTIUSER_INIT
# check if this FreeCAD version is already installed
${if} $MultiUser.Privileges == "Admin"
${orif} $MultiUser.Privileges == "Power"
ReadRegStr $0 HKLM "${APP_UNINST_KEY}" "DisplayIcon"
${else}
ReadRegStr $0 HKCU "${APP_UNINST_KEY}" "DisplayIcon"
# handle also the case that FreeCAD is already installed in HKLM
${if} $0 == ""
ReadRegStr $0 HKLM "${APP_UNINST_KEY}" "DisplayIcon"
${endif}
${endif}
${if} $0 != ""
# check if the uninstaller was acidentally deleted
# if so, don't bother the user if they really want to install a new FreeCAD over an existing one
# because they won't have a chance to deny this
StrCpy $4 $0 -16 # remove '\bin\FreeCAD.exe'
# (for FileCheck the variables $0 and $1 cannot be used)
!insertmacro FileCheck $5 "Uninstall-${APP_NAME}.exe" "$4" # macro from Utils.nsh
${if} $5 == "False"
Goto ForceInstallation
${endif}
# installing over an existing installation of the same FreeCAD release is not necessary
# if the users does this, they most probably have a problem with FreeCAD that can better be solved
# by reinstalling FreeCAD
# for beta and other test releases over-installing can even cause errors
MessageBox MB_YESNO|MB_DEFBUTTON2|MB_ICONEXCLAMATION "$(AlreadyInstalled)" /SD IDNO IDYES ForceInstallation
Abort
ForceInstallation:
${endif}
# check if there is an existing FreeCAD installation of the same FreeCAD series
# we usually don't release more than 10 versions so with 20 we are safe to check if a newer version is installed
IntOp $4 ${APP_VERSION_REVISION} + 20
${for} $5 0 $4
${if} $MultiUser.Privileges == "Admin"
${orif} $MultiUser.Privileges == "Power"
ReadRegStr $0 HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APP_NAME}${APP_VERSION_MAJOR}${APP_VERSION_MINOR}$5" "DisplayVersion"
# also check for an emergency release
${if} $0 == ""
ReadRegStr $0 HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APP_NAME}${APP_VERSION_MAJOR}${APP_VERSION_MINOR}$51" "DisplayVersion"
${endif}
${else}
ReadRegStr $0 HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APP_NAME}${APP_VERSION_MAJOR}${APP_VERSION_MINOR}$5" "DisplayVersion"
# also check for an emergency release
${if} $0 == ""
ReadRegStr $0 HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APP_NAME}${APP_VERSION_MAJOR}${APP_VERSION_MINOR}$51" "DisplayVersion"
${endif}
${endif}
${if} $0 != ""
StrCpy $R5 $0 # store the read version number
StrCpy $OldVersionNumber "${APP_VERSION_MAJOR}${APP_VERSION_MINOR}$5"
# we don't stop here because we want the latest installed version
${endif}
${next}
# NSIS cannot handle numbers with leading zero, thus cut it off before comparing
StrCpy $1 $OldVersionNumber "" 1
StrCpy $2 ${APP_SERIES_KEY} "" 1
${if} $1 > $2
# store the version number and reformat it temporarily for the error message
StrCpy $R0 $OldVersionNumber
StrCpy $OldVersionNumber $R5
MessageBox MB_OK|MB_ICONSTOP "$(NewerInstalled)" /SD IDOK
StrCpy $OldVersionNumber $R0
Abort
${endif}
# this can be reset to "true" in section SecDesktop
StrCpy $CreateDesktopIcon "false"
@@ -153,11 +143,19 @@ Function .onInit
Banner::destroy
${EndIf}
# if installer runs silent the post install mode page routine has to be called here
${If} ${Silent}
Call PostMultiUserPageInit
${endif}
FunctionEnd
# this function is called at first after starting the uninstaller
Function un.onInit
# Macro to investigate name of FreeCAD's preferences folders to be able remove them
!insertmacro UnAppPreSuff $AppPre $AppSuff # macro from Utils.nsh
!insertmacro MULTIUSER_UNINIT
# Check that FreeCAD is not currently running
@@ -175,14 +173,6 @@ Function un.onInit
SetRegView 64
${endif}
# set registry root key
${if} $MultiUser.Privileges == "Admin"
${orif} $MultiUser.Privileges == "Power"
SetShellVarContext all
${else}
SetShellVarContext current
${endif}
# Ascertain whether the user has sufficient privileges to uninstall.
# abort when FreeCAD was installed with admin permissions but the user doesn't have administrator privileges
ReadRegStr $0 HKLM "${APP_UNINST_KEY}" "DisplayVersion"
@@ -199,9 +189,6 @@ Function un.onInit
MessageBox MB_OK|MB_ICONEXCLAMATION "$(UnNotInRegistryLabel)" /SD IDOK
${endif}
${endif}
# Macro to investigate name of FreeCAD's preferences folders to be able remove them
!insertmacro UnAppPreSuff $AppPre $AppSuff # macro from Utils.nsh
# question message if the user really wants to uninstall FreeCAD
MessageBox MB_ICONQUESTION|MB_YESNO|MB_DEFBUTTON2 "$(UnReallyRemoveLabel)" /SD IDYES IDYES +2 # continue if yes

View File

@@ -246,23 +246,26 @@ Function un.DelAppPathSub
FunctionEnd
#--------------------------------
#source: https://nsis.sourceforge.io/Trim_quotes
!macro FileCheck Result FileName FilePath
# checks if a file exists, returns "True" or "False"
Function TrimQuotes
Exch $R0
Push $R1
Push $0
Push $1
StrCpy $0 ""
StrCpy $1 ""
FileOpen $0 "${FilePath}\${FileName}" r
${if} $0 = ""
StrCpy $1 "False"
${Else}
StrCpy $1 "True"
${endif}
FileClose $0
StrCpy ${Result} $1
Pop $1
Pop $0
StrCpy $R1 $R0 1
StrCmp $R1 `"` 0 +2
StrCpy $R0 $R0 `` 1
StrCpy $R1 $R0 1 -1
StrCmp $R1 `"` 0 +2
StrCpy $R0 $R0 -1
Pop $R1
Exch $R0
FunctionEnd
!macro _TrimQuotes Input Output
Push `${Input}`
Call TrimQuotes
Pop ${Output}
!macroend
!define TrimQuotes `!insertmacro _TrimQuotes`