diff --git a/build-aux/speedo/w32/g4wihelp.c b/build-aux/speedo/w32/g4wihelp.c index 012e4af0b..d62d03647 100644 --- a/build-aux/speedo/w32/g4wihelp.c +++ b/build-aux/speedo/w32/g4wihelp.c @@ -964,10 +964,8 @@ read_w32_registry_string (HKEY root, const char *dir, const char *name) #define ENV_REG "SYSTEM\\CurrentControlSet\\Control\\" \ "Session Manager\\Environment" /* The following setting can be used for a per-user setting. */ -#if 0 -#define ENV_HK HKEY_CURRENT_USER -#define ENV_REG "Environment" -#endif +#define ENV_HK_USER HKEY_CURRENT_USER +#define ENV_REG_USER "Environment" /* Due to a bug in Windows7 (kb 2685893) we better put a lower limit than 8191 on the maximum length of the PATH variable. Note, that depending on the used toolchain we used to had a 259 byte limit in @@ -979,12 +977,16 @@ path_add (HWND hwndParent, int string_size, char *variables, stack_t **stacktop, extra_parameters_t *extra) { char dir[PATH_LENGTH_LIMIT]; + char is_user_install[2]; char *path; char *path_new; int path_new_size; char *comp; const char delims[] = ";"; + int is_user; HKEY key_handle = 0; + HKEY root_key; + const char *env_reg; g_hwndParent = hwndParent; EXDLL_INIT(); @@ -997,13 +999,26 @@ path_add (HWND hwndParent, int string_size, char *variables, if (popstring (dir, sizeof (dir))) return; -/* MessageBox (g_hwndParent, "XXX 2", 0, MB_OK); */ + /* The expected stack layout: HKEY component. */ + if (popstring (is_user_install, sizeof (is_user_install))) + return; + + if (!strcmp(is_user_install, "1")) + { + root_key = ENV_HK_USER; + env_reg = ENV_REG_USER; + } + else + { + root_key = ENV_HK; + env_reg = ENV_REG; + } + + path = read_w32_registry_string (root_key, env_reg, "Path"); - path = read_w32_registry_string (ENV_HK, ENV_REG, "Path"); if (! path) { - MessageBox (g_hwndParent, "No PATH variable found", 0, MB_OK); - return; + path = strdup (""); } /* MessageBox (g_hwndParent, "XXX 3", 0, MB_OK); */ @@ -1041,6 +1056,8 @@ path_add (HWND hwndParent, int string_size, char *variables, do { /* MessageBox (g_hwndParent, comp, 0, MB_OK); */ + if (!comp) + break; if (!strcmp (comp, dir)) { @@ -1053,10 +1070,8 @@ path_add (HWND hwndParent, int string_size, char *variables, while (comp); free (path); -/* MessageBox (g_hwndParent, "XXX 8", 0, MB_OK); */ - - /* Set a key for our CLSID. */ - RegCreateKey (ENV_HK, ENV_REG, &key_handle); + /* Update the path key. */ + RegCreateKey (root_key, env_reg, &key_handle); RegSetValueEx (key_handle, "Path", 0, REG_EXPAND_SZ, path_new, path_new_size); RegCloseKey (key_handle); @@ -1074,6 +1089,7 @@ path_remove (HWND hwndParent, int string_size, char *variables, stack_t **stacktop, extra_parameters_t *extra) { char dir[PATH_LENGTH_LIMIT]; + char is_user_install[2]; char *path; char *path_new; int path_new_size; @@ -1082,6 +1098,8 @@ path_remove (HWND hwndParent, int string_size, char *variables, HKEY key_handle = 0; int changed = 0; int count = 0; + HKEY root_key; + const char *env_reg; g_hwndParent = hwndParent; EXDLL_INIT(); @@ -1092,7 +1110,25 @@ path_remove (HWND hwndParent, int string_size, char *variables, if (popstring (dir, sizeof (dir))) return; - path = read_w32_registry_string (ENV_HK, ENV_REG, "Path"); + /* The expected stack layout: HKEY component. */ + if (popstring (is_user_install, sizeof (is_user_install))) + return; + + if (!strcmp(is_user_install, "1")) + { + root_key = ENV_HK_USER; + env_reg = ENV_REG_USER; + } + else + { + root_key = ENV_HK; + env_reg = ENV_REG; + } + + path = read_w32_registry_string (root_key, env_reg, "Path"); + + if (!path) + return; /* Old path plus semicolon plus dir plus terminating nul. */ path_new_size = strlen (path) + 1; path_new = malloc (path_new_size); @@ -1126,7 +1162,7 @@ path_remove (HWND hwndParent, int string_size, char *variables, return; /* Set a key for our CLSID. */ - RegCreateKey (ENV_HK, ENV_REG, &key_handle); + RegCreateKey (root_key, env_reg, &key_handle); RegSetValueEx (key_handle, "Path", 0, REG_EXPAND_SZ, path_new, path_new_size); RegCloseKey (key_handle); diff --git a/build-aux/speedo/w32/inst.nsi b/build-aux/speedo/w32/inst.nsi index 7716f7f0e..297ef06ae 100644 --- a/build-aux/speedo/w32/inst.nsi +++ b/build-aux/speedo/w32/inst.nsi @@ -1,5 +1,6 @@ # inst.nsi - Installer for GnuPG on Windows. -*- coding: latin-1; -*- # Copyright (C) 2005, 2014 g10 Code GmbH +# 2017 Intevation GmbH # # This file is part of GnuPG. # @@ -42,7 +43,7 @@ !define PRETTY_PACKAGE "GNU Privacy Guard" !define PRETTY_PACKAGE_SHORT "GnuPG" !define COMPANY "The GnuPG Project" -!define COPYRIGHT "Copyright (C) 2015 The GnuPG Project" +!define COPYRIGHT "Copyright (C) 2017 The GnuPG Project" !define DESCRIPTION "GnuPG: The GNU Privacy Guard for Windows" !define INSTALL_DIR "GnuPG" @@ -80,9 +81,6 @@ SetCompressor lzma # SetCompressorDictSize 8 !endif -# Include the generic parts. -!define HAVE_STARTMENU - # We use the modern UI. !include "MUI.nsh" @@ -90,6 +88,17 @@ SetCompressor lzma !include "LogicLib.nsh" !include "x64.nsh" +# We support user mode installation but prefer system wide +!define MULTIUSER_EXECUTIONLEVEL Highest +!define MULTIUSER_MUI +!define MULTIUSER_INSTALLMODE_COMMANDLINE +!define MULTIUSER_INSTALLMODE_DEFAULT_REGISTRY_KEY "Software\${PACKAGE_SHORT}" +!define MULTIUSER_INSTALLMODE_DEFAULT_REGISTRY_VALUENAME "" +!define MULTIUSER_INSTALLMODE_INSTDIR_REGISTRY_KEY "Software\${PACKAGE_SHORT}" +!define MULTIUSER_INSTALLMODE_INSTDIR_REGISTRY_VALUENAME "Install Directory" +!define MULTIUSER_INSTALLMODE_INSTDIR "${PACKAGE_SHORT}" +!include "MultiUser.nsh" + # Set the package name. Note that this name should not be suffixed # with the version because this would get displayed in the start menu. # Given that a slash in the name troubles Windows startmenu creation @@ -109,9 +118,6 @@ OutFile "${NAME}-${VERSION}_${BUILD_DATESTR}.exe" !endif InstallDir "$PROGRAMFILES\${INSTALL_DIR}" -InstallDirRegKey HKLM "Software\${PACKAGE_SHORT}" "Install Directory" - - # Add version information to the file properties. VIProductVersion "${PROD_VERSION}" VIAddVersionKey "ProductName" "${PRETTY_PACKAGE_SHORT} (${VERSION})" @@ -161,7 +167,7 @@ VIAddVersionKey "FileVersion" "${PROD_VERSION}" # We don't have MUI_PAGE_DIRECTORY -!ifdef HAVE_STARTMENU +!ifdef WITH_GUI Page custom CustomPageOptions @@ -169,7 +175,7 @@ Var STARTMENU_FOLDER !define MUI_PAGE_CUSTOMFUNCTION_PRE CheckIfStartMenuWanted !define MUI_STARTMENUPAGE_NODISABLE -!define MUI_STARTMENUPAGE_REGISTRY_ROOT "HKCU" +!define MUI_STARTMENUPAGE_REGISTRY_ROOT "SHCTX" !define MUI_STARTMENUPAGE_REGISTRY_KEY "Software\GnuPG" !define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "Start Menu Folder" # We need to set the Startmenu name explicitly because a slash in the @@ -354,6 +360,8 @@ FunctionEnd # OS version without the need for an Administrator is in use. Print a # diagnostic if this is not the case and abort installation. Function PrintNonAdminWarning + Var /GLOBAL is_user_install + StrCpy $is_user_install "0" ClearErrors UserInfo::GetName IfErrors leave @@ -361,9 +369,11 @@ Function PrintNonAdminWarning UserInfo::GetAccountType Pop $1 StrCmp $1 "Admin" leave +1 - MessageBox MB_OK "$(T_AdminNeeded)" - Quit - + MessageBox MB_YESNO "$(T_AdminWanted)" IDNO exit + StrCpy $is_user_install "1" + goto leave + exit: + Quit leave: FunctionEnd @@ -446,24 +456,30 @@ LangString T_FoundExistingVersion ${LANG_GERMAN} \ eine neuere oder dieselbe Version handelt.)" LangString T_FoundExistingVersionB ${LANG_ENGLISH} \ "A version of GnuPG has already been installed on the system. \ - There will be no problem installing and thus overwriting this \ - Version. $\r$\n\ + $\r$\n\ $\r$\n\ Do you want to continue installing GnuPG?" LangString T_FoundExistingVersionB ${LANG_GERMAN} \ "Eine Version von GnuPG ist hier bereits installiert. \ - Es ist problemlos möglich, die Installation fortzuführen. $\r$\n\ + $\r$\n\ $\r$\n\ Möchten die die Installation von GnuPG fortführen?" # From Function PrintNonAdminWarning -LangString T_AdminNeeded ${LANG_ENGLISH} \ - "Warning: Administrator permissions required for a successful installation" -LangString T_AdminNeeded ${LANG_GERMAN} \ - "Achtung: Für eine erfolgreiche Installation werden \ - Administratorrechte benötigt." +LangString T_AdminWanted ${LANG_ENGLISH} \ + "Warning: It is recommended to install GnuPG system-wide with \ + administrator rights. \ + $\r$\n\ + $\r$\n\ + Do you want to continue installing GnuPG without administrator rights?" +LangString T_AdminWanted ${LANG_GERMAN} \ + "Achtung: Es wird empfohlen GnuPG systemweit mit \ + Administratorrechten zu installieren. \ + $\r$\n\ + $\r$\n\ + Möchten die die Installation von GnuPG ohne Administratorrechte fortführen?" # From Function PrintCloseOtherApps LangString T_CloseOtherApps ${LANG_ENGLISH} \ @@ -505,7 +521,7 @@ FunctionEnd # Input - head of the stack Function AddToPath Exch $0 - g4wihelp::path_add "$0" + g4wihelp::path_add "$0" $is_user_install StrCmp $R5 "0" add_to_path_done SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 add_to_path_done: @@ -516,8 +532,24 @@ FunctionEnd # RemoveFromPath - Remove a given dir from the path # Input: head of the stack Function un.RemoveFromPath + ClearErrors + UserInfo::GetName + IfErrors remove_admin + Pop $0 + UserInfo::GetAccountType + Pop $1 + StrCmp $1 "Admin" remove_admin remove_user + +remove_admin: Exch $0 - g4wihelp::path_remove "$0" + g4wihelp::path_remove "$0" "0" + goto remove_done +remove_user: + Exch $0 + g4wihelp::path_remove "$0" "1" + goto remove_done + +remove_done: StrCmp $R5 "0" remove_from_path_done SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 remove_from_path_done: @@ -540,7 +572,7 @@ Section "-gnupginst" FileWrite $0 "${VERSION}$\r$\n" FileClose $0 - WriteRegStr HKLM "Software\GnuPG" "Install Directory" $INSTDIR + WriteRegStr SHCTX "Software\GnuPG" "Install Directory" $INSTDIR # If we are reinstalling, try to kill a possible running gpa using # an already installed gpa. @@ -1381,7 +1413,7 @@ Section "-un.gnupginst" RMDir "$INSTDIR" # Clean the registry. - DeleteRegValue HKLM "Software\GNU\GnuPG" "Install Directory" + DeleteRegValue SHCTX "Software\GNU\GnuPG" "Install Directory" SectionEnd @@ -1409,8 +1441,25 @@ Function .onInit !insertmacro MUI_INSTALLOPTIONS_EXTRACT "${W32_SRCDIR}/inst-options.ini" #Call CalcDepends + + Var /GLOBAL changed_dir + # Check if the install directory was modified on the command line + StrCmp "$INSTDIR" "$PROGRAMFILES\${INSTALL_DIR}" unmodified 0 + # It is modified. Save that value. + StrCpy $changed_dir "$INSTDIR" + + # MULITUSER_INIT overwrites directory setting from command line + !insertmacro MULTIUSER_INIT + StrCpy $INSTDIR "$changed_dir" + goto initDone +unmodified: + !insertmacro MULTIUSER_INIT +initDone: FunctionEnd +Function "un.onInit" + !insertmacro MULTIUSER_UNINIT +FunctionEnd #Function .onInstFailed # Delete $TEMP\gpgspltmp.wav @@ -1439,13 +1488,6 @@ FunctionEnd !ifdef WITH_GUI Section "-startmenu" -!ifdef HAVE_STARTMENU - # Make sure that the context of the automatic variables has been set to - # the "all users" shell folder. This guarantees that the menu gets written - # for all users. We have already checked that we are running as Admin; or - # we printed a warning that installation will not succeed. - SetShellVarContext all - # Check if the start menu entries where requested. !insertmacro MUI_INSTALLOPTIONS_READ $R0 "${W32_SRCDIR}/inst-options.ini" \ "Field 2" "State" @@ -1517,7 +1559,6 @@ no_gpa_quicklaunch: no_quick_launch: -!endif SectionEnd !endif @@ -1533,30 +1574,23 @@ Section # Windows Add/Remove Programs support StrCpy $MYTMP "Software\Microsoft\Windows\CurrentVersion\Uninstall\GnuPG" - WriteRegExpandStr HKLM $MYTMP "UninstallString" '"$INSTDIR\gnupg-uninstall.exe"' - WriteRegExpandStr HKLM $MYTMP "InstallLocation" "$INSTDIR" - WriteRegStr HKLM $MYTMP "DisplayName" "${PRETTY_PACKAGE}" + WriteRegExpandStr SHCTX $MYTMP "UninstallString" '"$INSTDIR\gnupg-uninstall.exe"' + WriteRegExpandStr SHCTX $MYTMP "InstallLocation" "$INSTDIR" + WriteRegStr SHCTX $MYTMP "DisplayName" "${PRETTY_PACKAGE}" !ifdef WITH_GUI - WriteRegStr HKLM $MYTMP "DisplayIcon" "$INSTDIR\bin\gpa.exe,0" + WriteRegStr SHCTX $MYTMP "DisplayIcon" "$INSTDIR\bin\gpa.exe,0" +!else + WriteRegStr SHCTX $MYTMP "DisplayIcon" "$INSTDIR\bin\gpg.exe,0" !endif - WriteRegStr HKLM $MYTMP "DisplayVersion" "${VERSION}" - WriteRegStr HKLM $MYTMP "Publisher" "The GnuPG Project" - WriteRegStr HKLM $MYTMP "URLInfoAbout" "https://gnupg.org" - WriteRegDWORD HKLM $MYTMP "NoModify" "1" - WriteRegDWORD HKLM $MYTMP "NoRepair" "1" + WriteRegStr SHCTX $MYTMP "DisplayVersion" "${VERSION}" + WriteRegStr SHCTX $MYTMP "Publisher" "The GnuPG Project" + WriteRegStr SHCTX $MYTMP "URLInfoAbout" "https://gnupg.org" + WriteRegDWORD SHCTX $MYTMP "NoModify" "1" + WriteRegDWORD SHCTX $MYTMP "NoRepair" "1" SectionEnd - Section Uninstall - !ifdef WITH_GUI -!ifdef HAVE_STARTMENU - # Make sure that the context of the automatic variables has been set to - # the "all users" shell folder. This guarantees that the menu gets written - # for all users. We have already checked that we are running as Admin; or - # we printed a warning that installation will not succeed. - SetShellVarContext all - #--------------------------------------------------- # Delete the menu entries and any empty parent menus #--------------------------------------------------- @@ -1574,7 +1608,7 @@ Section Uninstall StrCmp $MYTMP $SMPROGRAMS startMenuDeleteLoopDone startMenuDeleteLoop startMenuDeleteLoopDone: - DeleteRegValue HKLM "Software\GNU\GnuPG" "Start Menu Folder" + DeleteRegValue SHCTX "Software\GNU\GnuPG" "Start Menu Folder" # Delete Desktop links. Delete "$DESKTOP\GPA.lnk" @@ -1586,15 +1620,14 @@ Section Uninstall Delete "$QUICKLAUNCH\GPA.lnk" no_quick_launch_uninstall: -!endif !endif Delete "$INSTDIR\gnupg-uninstall.exe" RMDir "$INSTDIR" # Clean the registry. - DeleteRegValue HKLM "Software\GnuPG" "Install Directory" - DeleteRegKey /ifempty HKLM "Software\GnuPG" + DeleteRegValue SHCTX "Software\GnuPG" "Install Directory" + DeleteRegKey /ifempty SHCTX "Software\GnuPG" # Remove Windows Add/Remove Programs support. - DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\GnuPG" + DeleteRegKey SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\GnuPG" SectionEnd