diff --git a/src/WindowsInstaller/FreeCAD-installer.nsi b/src/WindowsInstaller/FreeCAD-installer.nsi index 349cd84a05..c078838f74 100644 --- a/src/WindowsInstaller/FreeCAD-installer.nsi +++ b/src/WindowsInstaller/FreeCAD-installer.nsi @@ -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}" diff --git a/src/WindowsInstaller/include/declarations.nsh b/src/WindowsInstaller/include/declarations.nsh index dfc96e540d..3832d33fc3 100644 --- a/src/WindowsInstaller/include/declarations.nsh +++ b/src/WindowsInstaller/include/declarations.nsh @@ -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" diff --git a/src/WindowsInstaller/include/gui.nsh b/src/WindowsInstaller/include/gui.nsh index 7262eaba3a..934a218094 100644 --- a/src/WindowsInstaller/include/gui.nsh +++ b/src/WindowsInstaller/include/gui.nsh @@ -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. diff --git a/src/WindowsInstaller/include/init.nsh b/src/WindowsInstaller/include/init.nsh index f11153ef46..439736d658 100644 --- a/src/WindowsInstaller/include/init.nsh +++ b/src/WindowsInstaller/include/init.nsh @@ -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 diff --git a/src/WindowsInstaller/include/utils.nsh b/src/WindowsInstaller/include/utils.nsh index 98b868352a..a454d95bb6 100644 --- a/src/WindowsInstaller/include/utils.nsh +++ b/src/WindowsInstaller/include/utils.nsh @@ -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`