diff --git a/Docs/src/history.but b/Docs/src/history.but index 76a9dc20..4db08425 100644 --- a/Docs/src/history.but +++ b/Docs/src/history.but @@ -12,6 +12,8 @@ Released on ? ?th, 2020 \S2{} Major Changes +\b \cw{DeleteRegKey /ifempty} now also checks for values, not just subkeys. Use \cw{/ifnosubkeys} for the old behavior. + \b Added \R{getknownfolderpath}{GetKnownFolderPath} \S2{} Minor Changes diff --git a/Docs/src/registry.but b/Docs/src/registry.but index 0fabe06a..f8890780 100644 --- a/Docs/src/registry.but +++ b/Docs/src/registry.but @@ -29,9 +29,9 @@ Deletes the string str_name from section [section_name] from ini_filename. If th \S2{deleteregkey} DeleteRegKey -\c [/ifempty] root_key subkey +\c [/ifempty | /ifnosubkeys | /ifnovalues] root_key subkey -Deletes a registry key. If /ifempty is specified, the registry key will only be deleted if it has no subkeys (otherwise, the whole registry tree will be removed). Valid values for root_key are listed under \R{writeregstr}{WriteRegStr}. The error flag is set if the key could not be removed from the registry (or if it didn't exist to begin with). +Deletes a registry key. If /ifempty is specified, the registry key will only be deleted if it has no subkeys and no values (otherwise, the whole registry tree will be removed). Valid values for root_key are listed under \R{writeregstr}{WriteRegStr}. The error flag is set if the key could not be removed from the registry (or if it didn't exist to begin with). \c DeleteRegKey HKLM "Software\My Company\My Software" \c DeleteRegKey /ifempty HKLM "Software\A key that might have subkeys" diff --git a/Source/exehead/exec.c b/Source/exehead/exec.c index ab19c093..964c6b2e 100644 --- a/Source/exehead/exec.c +++ b/Source/exehead/exec.c @@ -176,33 +176,42 @@ static HKEY NSISCALL RegCreateScriptKey(int RootKey, LPCTSTR SubKey, REGSAM RS) // RegDeleteKeyEx on 32-bit Windows accepts but ignores the KEY_WOW64_xxKEY flags and always uses the // one and only native key. Our RegKeyOpen will intentionally fail if a incompatible WoW64 flag is used. #define DRTF_ONLYIFNOSUBKEYS DELREGKEY_ONLYIFNOSUBKEYS +#define DRTF_ONLYIFNOVALUES DELREGKEY_ONLYIFNOVALUES static LONG NSISCALL DeleteRegTree(HKEY hThisKey, LPCTSTR SubKey, REGSAM SamviewAndFlags) { HKEY hKey; - UINT onlyifempty = SamviewAndFlags & DRTF_ONLYIFNOSUBKEYS; + UINT onlyifnosubkeys = SamviewAndFlags & DRTF_ONLYIFNOSUBKEYS; + UINT onlyifnovalues = SamviewAndFlags & DRTF_ONLYIFNOVALUES, valuesexistcheckinsubkeys = TRUE; REGSAM samview = SamviewAndFlags & (KEY_WOW64_32KEY|KEY_WOW64_64KEY); - LONG retval = RegKeyOpen(hThisKey, SubKey, KEY_ENUMERATE_SUB_KEYS|samview, &hKey); + LONG retval = RegKeyOpen(hThisKey, SubKey, KEY_ENUMERATE_SUB_KEYS|KEY_QUERY_VALUE|samview, &hKey); if (retval == ERROR_SUCCESS) { TCHAR child[MAX_PATH+1]; // NB - don't change this to static (recursive function) + if (onlyifnovalues) + { + DWORD cchName = 0; + retval = RegEnumValue(hKey, 0, child, &cchName, NULL, NULL, NULL, NULL); + if (retval != ERROR_NO_MORE_ITEMS) goto notempty; + if (!valuesexistcheckinsubkeys) SamviewAndFlags &= ~DRTF_ONLYIFNOVALUES; + } while (RegEnumKey(hKey, 0, child, COUNTOF(child)) == ERROR_SUCCESS) { - if (onlyifempty) return (RegCloseKey(hKey), ERROR_CAN_NOT_COMPLETE); + if (onlyifnosubkeys) notempty: return (RegCloseKey(hKey), ERROR_CAN_NOT_COMPLETE); if ((retval = DeleteRegTree(hKey, child, SamviewAndFlags)) != ERROR_SUCCESS) break; } RegCloseKey(hKey); { - typedef LONG (WINAPI * RegDeleteKeyExPtr)(HKEY, LPCTSTR, REGSAM, DWORD); - RegDeleteKeyExPtr RDKE = (RegDeleteKeyExPtr) - #ifdef _WIN64 - RegDeleteKeyEx; - #else + typedef LONG (WINAPI * RegDeleteKeyExType)(HKEY, LPCTSTR, REGSAM, DWORD); + RegDeleteKeyExType RDKE = (RegDeleteKeyExType) + #if !defined(_WIN64) || defined(_M_IA64) myGetProcAddress(MGA_RegDeleteKeyEx); - #endif - if (RDKE) - retval = RDKE(hThisKey, SubKey, samview, 0); - else + if (!RDKE) retval = RegDeleteKey(hThisKey, SubKey); + else + #else + RegDeleteKeyEx; + #endif + retval = RDKE(hThisKey, SubKey, samview, 0); } } return retval; diff --git a/Source/exehead/fileform.h b/Source/exehead/fileform.h index dcb9e11c..a33797a8 100644 --- a/Source/exehead/fileform.h +++ b/Source/exehead/fileform.h @@ -550,8 +550,9 @@ typedef struct { #define HKLMANY MAKEREGROOTVIEW(HKEY_LOCAL_MACHINE, REGROOTVIEW32|REGROOTVIEW64) #define DELREG_VALUE 0 // TOK_DELETEREGVALUE #define DELREG_KEY 1 // TOK_DELETEREGKEY -#define DELREGKEY_ONLYIFNOSUBKEYS 1 // Shifted and stored as 2 in the binary for compatibility with <= 3.1 -#define DELREGKEYFLAGSSHIFT 1 // parm4 is shifted so exehead can remove the DELREG_KEY bit +#define DELREGKEY_ONLYIFNOSUBKEYS 0x01 // Note: Shifted (stored as 2 in the binary) for compatibility with <= v3.1 +#define DELREGKEY_ONLYIFNOVALUES 0x02 +#define DELREGKEYFLAGSSHIFT 1 // exehead removes the DELREG_KEY bit in parm4 by shifting. After shifting the bits are DELREGKEY_*. #ifdef NSIS_SUPPORT_CREATESHORTCUT diff --git a/Source/exehead/util.c b/Source/exehead/util.c index a653556f..08e872f2 100644 --- a/Source/exehead/util.c +++ b/Source/exehead/util.c @@ -1166,6 +1166,8 @@ struct MGA_FUNC MGA_FUNCS[] = { #ifndef _WIN64 {"KERNEL32", "GetDiskFreeSpaceExW"}, {"KERNEL32", "GetUserDefaultUILanguage"}, +#endif +#if !defined(_WIN64) || defined(_M_IA64) {"ADVAPI32", "RegDeleteKeyExW"}, #endif {"ADVAPI32", "InitiateShutdownW"}, diff --git a/Source/exehead/util.h b/Source/exehead/util.h index 703d1dec..b8b3696a 100644 --- a/Source/exehead/util.h +++ b/Source/exehead/util.h @@ -164,6 +164,8 @@ enum myGetProcAddressFunctions { #ifndef _WIN64 MGA_GetDiskFreeSpaceEx, MGA_GetUserDefaultUILanguage, +#endif +#if !defined(_WIN64) || defined(_M_IA64) MGA_RegDeleteKeyEx, #endif MGA_InitiateShutdown, diff --git a/Source/script.cpp b/Source/script.cpp index 66f5945d..74d82712 100644 --- a/Source/script.cpp +++ b/Source/script.cpp @@ -4319,11 +4319,15 @@ int CEXEBuild::doCommand(int which_token, LineParser &line) int a=1, iskeyop; if ((iskeyop = which_token == TOK_DELETEREGKEY)) { - TCHAR *s=line.gettoken_str(a); - if (s[0] == _T('/')) + for (;; ++a) { - if (_tcsicmp(s,_T("/ifempty"))) PRINTHELP() - a++, ent.offsets[4]|=(DELREGKEY_ONLYIFNOSUBKEYS<