1
0
mirror of git://git.gnupg.org/gnupg.git synced 2024-06-06 23:17:47 +02:00

speedo,w32: Allow installation as normal user

* build-aux/speedo/w32/g4wihelp.c (ENV_HK_USER, ENV_REG_USER):
New defines.
(path_add): Handle is_user_install variable. Don't abort
if Path reg key does not exist. Fix crash if Path reg key
does not contain a semicolon.
(path_remove): Handle is_user_install variable. Fix crash
if Path reg key does not exist.
* build-aux/speedo/w32/inst.nsi: Remove obsolete HAVE_STARTMENU
this was double guarded with WITH_GUI. Add Multiuser plugin and
defines for this. Use SHCTX instead of HKLM / HKCU.
(PrintNonAdminWarning): Only Warn and don't abort.

--
The default is still to install as Adminstrator system wide
but the user now has the option to explicitly install GnuPG without
Administrator rights. A warning will be shown in that case but
a user may continue.

A per user install is by default under %LOCALAPPDATA%\GnuPG

Related Task: T2971

Signed-off-by: Andre Heinecke <aheinecke@intevation.de>
This commit is contained in:
Andre Heinecke 2017-05-03 14:40:16 +02:00
parent 201f868030
commit cacfd4bce9
No known key found for this signature in database
GPG Key ID: 2978E9D40CBABA5C
2 changed files with 138 additions and 69 deletions

View File

@ -964,10 +964,8 @@ read_w32_registry_string (HKEY root, const char *dir, const char *name)
#define ENV_REG "SYSTEM\\CurrentControlSet\\Control\\" \ #define ENV_REG "SYSTEM\\CurrentControlSet\\Control\\" \
"Session Manager\\Environment" "Session Manager\\Environment"
/* The following setting can be used for a per-user setting. */ /* The following setting can be used for a per-user setting. */
#if 0 #define ENV_HK_USER HKEY_CURRENT_USER
#define ENV_HK HKEY_CURRENT_USER #define ENV_REG_USER "Environment"
#define ENV_REG "Environment"
#endif
/* Due to a bug in Windows7 (kb 2685893) we better put a lower limit /* 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 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 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) stack_t **stacktop, extra_parameters_t *extra)
{ {
char dir[PATH_LENGTH_LIMIT]; char dir[PATH_LENGTH_LIMIT];
char is_user_install[2];
char *path; char *path;
char *path_new; char *path_new;
int path_new_size; int path_new_size;
char *comp; char *comp;
const char delims[] = ";"; const char delims[] = ";";
int is_user;
HKEY key_handle = 0; HKEY key_handle = 0;
HKEY root_key;
const char *env_reg;
g_hwndParent = hwndParent; g_hwndParent = hwndParent;
EXDLL_INIT(); EXDLL_INIT();
@ -997,13 +999,26 @@ path_add (HWND hwndParent, int string_size, char *variables,
if (popstring (dir, sizeof (dir))) if (popstring (dir, sizeof (dir)))
return; 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) if (! path)
{ {
MessageBox (g_hwndParent, "No PATH variable found", 0, MB_OK); path = strdup ("");
return;
} }
/* MessageBox (g_hwndParent, "XXX 3", 0, MB_OK); */ /* MessageBox (g_hwndParent, "XXX 3", 0, MB_OK); */
@ -1041,6 +1056,8 @@ path_add (HWND hwndParent, int string_size, char *variables,
do do
{ {
/* MessageBox (g_hwndParent, comp, 0, MB_OK); */ /* MessageBox (g_hwndParent, comp, 0, MB_OK); */
if (!comp)
break;
if (!strcmp (comp, dir)) if (!strcmp (comp, dir))
{ {
@ -1053,10 +1070,8 @@ path_add (HWND hwndParent, int string_size, char *variables,
while (comp); while (comp);
free (path); free (path);
/* MessageBox (g_hwndParent, "XXX 8", 0, MB_OK); */ /* Update the path key. */
RegCreateKey (root_key, env_reg, &key_handle);
/* Set a key for our CLSID. */
RegCreateKey (ENV_HK, ENV_REG, &key_handle);
RegSetValueEx (key_handle, "Path", 0, REG_EXPAND_SZ, RegSetValueEx (key_handle, "Path", 0, REG_EXPAND_SZ,
path_new, path_new_size); path_new, path_new_size);
RegCloseKey (key_handle); RegCloseKey (key_handle);
@ -1074,6 +1089,7 @@ path_remove (HWND hwndParent, int string_size, char *variables,
stack_t **stacktop, extra_parameters_t *extra) stack_t **stacktop, extra_parameters_t *extra)
{ {
char dir[PATH_LENGTH_LIMIT]; char dir[PATH_LENGTH_LIMIT];
char is_user_install[2];
char *path; char *path;
char *path_new; char *path_new;
int path_new_size; int path_new_size;
@ -1082,6 +1098,8 @@ path_remove (HWND hwndParent, int string_size, char *variables,
HKEY key_handle = 0; HKEY key_handle = 0;
int changed = 0; int changed = 0;
int count = 0; int count = 0;
HKEY root_key;
const char *env_reg;
g_hwndParent = hwndParent; g_hwndParent = hwndParent;
EXDLL_INIT(); EXDLL_INIT();
@ -1092,7 +1110,25 @@ path_remove (HWND hwndParent, int string_size, char *variables,
if (popstring (dir, sizeof (dir))) if (popstring (dir, sizeof (dir)))
return; 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. */ /* Old path plus semicolon plus dir plus terminating nul. */
path_new_size = strlen (path) + 1; path_new_size = strlen (path) + 1;
path_new = malloc (path_new_size); path_new = malloc (path_new_size);
@ -1126,7 +1162,7 @@ path_remove (HWND hwndParent, int string_size, char *variables,
return; return;
/* Set a key for our CLSID. */ /* 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, RegSetValueEx (key_handle, "Path", 0, REG_EXPAND_SZ,
path_new, path_new_size); path_new, path_new_size);
RegCloseKey (key_handle); RegCloseKey (key_handle);

View File

@ -1,5 +1,6 @@
# inst.nsi - Installer for GnuPG on Windows. -*- coding: latin-1; -*- # inst.nsi - Installer for GnuPG on Windows. -*- coding: latin-1; -*-
# Copyright (C) 2005, 2014 g10 Code GmbH # Copyright (C) 2005, 2014 g10 Code GmbH
# 2017 Intevation GmbH
# #
# This file is part of GnuPG. # This file is part of GnuPG.
# #
@ -42,7 +43,7 @@
!define PRETTY_PACKAGE "GNU Privacy Guard" !define PRETTY_PACKAGE "GNU Privacy Guard"
!define PRETTY_PACKAGE_SHORT "GnuPG" !define PRETTY_PACKAGE_SHORT "GnuPG"
!define COMPANY "The GnuPG Project" !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 DESCRIPTION "GnuPG: The GNU Privacy Guard for Windows"
!define INSTALL_DIR "GnuPG" !define INSTALL_DIR "GnuPG"
@ -80,9 +81,6 @@ SetCompressor lzma
# SetCompressorDictSize 8 # SetCompressorDictSize 8
!endif !endif
# Include the generic parts.
!define HAVE_STARTMENU
# We use the modern UI. # We use the modern UI.
!include "MUI.nsh" !include "MUI.nsh"
@ -90,6 +88,17 @@ SetCompressor lzma
!include "LogicLib.nsh" !include "LogicLib.nsh"
!include "x64.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 # Set the package name. Note that this name should not be suffixed
# with the version because this would get displayed in the start menu. # with the version because this would get displayed in the start menu.
# Given that a slash in the name troubles Windows startmenu creation # Given that a slash in the name troubles Windows startmenu creation
@ -109,9 +118,6 @@ OutFile "${NAME}-${VERSION}_${BUILD_DATESTR}.exe"
!endif !endif
InstallDir "$PROGRAMFILES\${INSTALL_DIR}" InstallDir "$PROGRAMFILES\${INSTALL_DIR}"
InstallDirRegKey HKLM "Software\${PACKAGE_SHORT}" "Install Directory"
# Add version information to the file properties. # Add version information to the file properties.
VIProductVersion "${PROD_VERSION}" VIProductVersion "${PROD_VERSION}"
VIAddVersionKey "ProductName" "${PRETTY_PACKAGE_SHORT} (${VERSION})" VIAddVersionKey "ProductName" "${PRETTY_PACKAGE_SHORT} (${VERSION})"
@ -161,7 +167,7 @@ VIAddVersionKey "FileVersion" "${PROD_VERSION}"
# We don't have MUI_PAGE_DIRECTORY # We don't have MUI_PAGE_DIRECTORY
!ifdef HAVE_STARTMENU !ifdef WITH_GUI
Page custom CustomPageOptions Page custom CustomPageOptions
@ -169,7 +175,7 @@ Var STARTMENU_FOLDER
!define MUI_PAGE_CUSTOMFUNCTION_PRE CheckIfStartMenuWanted !define MUI_PAGE_CUSTOMFUNCTION_PRE CheckIfStartMenuWanted
!define MUI_STARTMENUPAGE_NODISABLE !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_KEY "Software\GnuPG"
!define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "Start Menu Folder" !define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "Start Menu Folder"
# We need to set the Startmenu name explicitly because a slash in the # 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 # OS version without the need for an Administrator is in use. Print a
# diagnostic if this is not the case and abort installation. # diagnostic if this is not the case and abort installation.
Function PrintNonAdminWarning Function PrintNonAdminWarning
Var /GLOBAL is_user_install
StrCpy $is_user_install "0"
ClearErrors ClearErrors
UserInfo::GetName UserInfo::GetName
IfErrors leave IfErrors leave
@ -361,9 +369,11 @@ Function PrintNonAdminWarning
UserInfo::GetAccountType UserInfo::GetAccountType
Pop $1 Pop $1
StrCmp $1 "Admin" leave +1 StrCmp $1 "Admin" leave +1
MessageBox MB_OK "$(T_AdminNeeded)" MessageBox MB_YESNO "$(T_AdminWanted)" IDNO exit
Quit StrCpy $is_user_install "1"
goto leave
exit:
Quit
leave: leave:
FunctionEnd FunctionEnd
@ -446,24 +456,30 @@ LangString T_FoundExistingVersion ${LANG_GERMAN} \
eine neuere oder dieselbe Version handelt.)" eine neuere oder dieselbe Version handelt.)"
LangString T_FoundExistingVersionB ${LANG_ENGLISH} \ LangString T_FoundExistingVersionB ${LANG_ENGLISH} \
"A version of GnuPG has already been installed on the system. \ "A version of GnuPG has already been installed on the system. \
There will be no problem installing and thus overwriting this \ $\r$\n\
Version. $\r$\n\
$\r$\n\ $\r$\n\
Do you want to continue installing GnuPG?" Do you want to continue installing GnuPG?"
LangString T_FoundExistingVersionB ${LANG_GERMAN} \ LangString T_FoundExistingVersionB ${LANG_GERMAN} \
"Eine Version von GnuPG ist hier bereits installiert. \ "Eine Version von GnuPG ist hier bereits installiert. \
Es ist problemlos möglich, die Installation fortzuführen. $\r$\n\ $\r$\n\
$\r$\n\ $\r$\n\
Möchten die die Installation von GnuPG fortführen?" Möchten die die Installation von GnuPG fortführen?"
# From Function PrintNonAdminWarning # From Function PrintNonAdminWarning
LangString T_AdminNeeded ${LANG_ENGLISH} \ LangString T_AdminWanted ${LANG_ENGLISH} \
"Warning: Administrator permissions required for a successful installation" "Warning: It is recommended to install GnuPG system-wide with \
LangString T_AdminNeeded ${LANG_GERMAN} \ administrator rights. \
"Achtung: Für eine erfolgreiche Installation werden \ $\r$\n\
Administratorrechte benötigt." $\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 # From Function PrintCloseOtherApps
LangString T_CloseOtherApps ${LANG_ENGLISH} \ LangString T_CloseOtherApps ${LANG_ENGLISH} \
@ -505,7 +521,7 @@ FunctionEnd
# Input - head of the stack # Input - head of the stack
Function AddToPath Function AddToPath
Exch $0 Exch $0
g4wihelp::path_add "$0" g4wihelp::path_add "$0" $is_user_install
StrCmp $R5 "0" add_to_path_done StrCmp $R5 "0" add_to_path_done
SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000
add_to_path_done: add_to_path_done:
@ -516,8 +532,24 @@ FunctionEnd
# RemoveFromPath - Remove a given dir from the path # RemoveFromPath - Remove a given dir from the path
# Input: head of the stack # Input: head of the stack
Function un.RemoveFromPath 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 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 StrCmp $R5 "0" remove_from_path_done
SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000
remove_from_path_done: remove_from_path_done:
@ -540,7 +572,7 @@ Section "-gnupginst"
FileWrite $0 "${VERSION}$\r$\n" FileWrite $0 "${VERSION}$\r$\n"
FileClose $0 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 # If we are reinstalling, try to kill a possible running gpa using
# an already installed gpa. # an already installed gpa.
@ -1381,7 +1413,7 @@ Section "-un.gnupginst"
RMDir "$INSTDIR" RMDir "$INSTDIR"
# Clean the registry. # Clean the registry.
DeleteRegValue HKLM "Software\GNU\GnuPG" "Install Directory" DeleteRegValue SHCTX "Software\GNU\GnuPG" "Install Directory"
SectionEnd SectionEnd
@ -1409,8 +1441,25 @@ Function .onInit
!insertmacro MUI_INSTALLOPTIONS_EXTRACT "${W32_SRCDIR}/inst-options.ini" !insertmacro MUI_INSTALLOPTIONS_EXTRACT "${W32_SRCDIR}/inst-options.ini"
#Call CalcDepends #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 FunctionEnd
Function "un.onInit"
!insertmacro MULTIUSER_UNINIT
FunctionEnd
#Function .onInstFailed #Function .onInstFailed
# Delete $TEMP\gpgspltmp.wav # Delete $TEMP\gpgspltmp.wav
@ -1439,13 +1488,6 @@ FunctionEnd
!ifdef WITH_GUI !ifdef WITH_GUI
Section "-startmenu" 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. # Check if the start menu entries where requested.
!insertmacro MUI_INSTALLOPTIONS_READ $R0 "${W32_SRCDIR}/inst-options.ini" \ !insertmacro MUI_INSTALLOPTIONS_READ $R0 "${W32_SRCDIR}/inst-options.ini" \
"Field 2" "State" "Field 2" "State"
@ -1517,7 +1559,6 @@ no_gpa_quicklaunch:
no_quick_launch: no_quick_launch:
!endif
SectionEnd SectionEnd
!endif !endif
@ -1533,30 +1574,23 @@ Section
# Windows Add/Remove Programs support # Windows Add/Remove Programs support
StrCpy $MYTMP "Software\Microsoft\Windows\CurrentVersion\Uninstall\GnuPG" StrCpy $MYTMP "Software\Microsoft\Windows\CurrentVersion\Uninstall\GnuPG"
WriteRegExpandStr HKLM $MYTMP "UninstallString" '"$INSTDIR\gnupg-uninstall.exe"' WriteRegExpandStr SHCTX $MYTMP "UninstallString" '"$INSTDIR\gnupg-uninstall.exe"'
WriteRegExpandStr HKLM $MYTMP "InstallLocation" "$INSTDIR" WriteRegExpandStr SHCTX $MYTMP "InstallLocation" "$INSTDIR"
WriteRegStr HKLM $MYTMP "DisplayName" "${PRETTY_PACKAGE}" WriteRegStr SHCTX $MYTMP "DisplayName" "${PRETTY_PACKAGE}"
!ifdef WITH_GUI !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 !endif
WriteRegStr HKLM $MYTMP "DisplayVersion" "${VERSION}" WriteRegStr SHCTX $MYTMP "DisplayVersion" "${VERSION}"
WriteRegStr HKLM $MYTMP "Publisher" "The GnuPG Project" WriteRegStr SHCTX $MYTMP "Publisher" "The GnuPG Project"
WriteRegStr HKLM $MYTMP "URLInfoAbout" "https://gnupg.org" WriteRegStr SHCTX $MYTMP "URLInfoAbout" "https://gnupg.org"
WriteRegDWORD HKLM $MYTMP "NoModify" "1" WriteRegDWORD SHCTX $MYTMP "NoModify" "1"
WriteRegDWORD HKLM $MYTMP "NoRepair" "1" WriteRegDWORD SHCTX $MYTMP "NoRepair" "1"
SectionEnd SectionEnd
Section Uninstall Section Uninstall
!ifdef WITH_GUI !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 # Delete the menu entries and any empty parent menus
#--------------------------------------------------- #---------------------------------------------------
@ -1574,7 +1608,7 @@ Section Uninstall
StrCmp $MYTMP $SMPROGRAMS startMenuDeleteLoopDone startMenuDeleteLoop StrCmp $MYTMP $SMPROGRAMS startMenuDeleteLoopDone startMenuDeleteLoop
startMenuDeleteLoopDone: startMenuDeleteLoopDone:
DeleteRegValue HKLM "Software\GNU\GnuPG" "Start Menu Folder" DeleteRegValue SHCTX "Software\GNU\GnuPG" "Start Menu Folder"
# Delete Desktop links. # Delete Desktop links.
Delete "$DESKTOP\GPA.lnk" Delete "$DESKTOP\GPA.lnk"
@ -1586,15 +1620,14 @@ Section Uninstall
Delete "$QUICKLAUNCH\GPA.lnk" Delete "$QUICKLAUNCH\GPA.lnk"
no_quick_launch_uninstall: no_quick_launch_uninstall:
!endif
!endif !endif
Delete "$INSTDIR\gnupg-uninstall.exe" Delete "$INSTDIR\gnupg-uninstall.exe"
RMDir "$INSTDIR" RMDir "$INSTDIR"
# Clean the registry. # Clean the registry.
DeleteRegValue HKLM "Software\GnuPG" "Install Directory" DeleteRegValue SHCTX "Software\GnuPG" "Install Directory"
DeleteRegKey /ifempty HKLM "Software\GnuPG" DeleteRegKey /ifempty SHCTX "Software\GnuPG"
# Remove Windows Add/Remove Programs support. # Remove Windows Add/Remove Programs support.
DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\GnuPG" DeleteRegKey SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\GnuPG"
SectionEnd SectionEnd