Two registry functions. First is a RegKeyExists function that will determine if a reg key exists without using the Registry plugin. The next one builds on that function, and can use SetACL to reset permissions on a key to allow you to delete it, ie the Enum\Root\LEGACY_ keys.
Should be self-explanatory how to use them. They use the same format as the Registry plugin, ie a full key path.
Release Notes:
Update 2008-04-06
-
Rewrote the functions so they no longer rely on the NSIS builtin registry functions. These functions are limited in that they cannot accept variables, and must be hardcoded.
I'll probably be updating this fairly regularly, adding new functions.
/**************************************************************
* Copyright Erik Pilsits 2008
***************************************************************
* ${RegKeyExists} "[full key path]" $var
*
* $var 0 - key does not exist
* 1 - key exists
***************************************************************
* Var setacl
* StrCpy $setacl "X:\path\to\SetACL.exe"
*
* ${SetACL_DeleteKey} "[full key path]" $var1 $var2
*
* $var1 [number] - nsExec return code
* "fail" - operation failed (key does not exist)
* $var2 0 - delete succeeded
* non-zero | "fail" - delete failed
***************************************************************
* LONG WINAPI RegOpenKeyEx(
* __in HKEY hKey,
* __in_opt LPCTSTR lpSubKey,
* __reserved DWORD ulOptions,
* __in REGSAM samDesired,
* __out PHKEY phkResult
* );
*
* LONG WINAPI RegCloseKey(
* __in HKEY hKey
* );
*
* LSTATUS SHDeleteKey(
* __in HKEY hkey,
* __in LPCTSTR pszSubKey
* );
***************************************************************/
!include LogicLib.nsh
!include WordFunc.nsh
!insertmacro WordFind
!define KEY_ALL_ACCESS "0xF003F"
!define KEY_CREATE_SUB_KEY "0x0004"
!define KEY_ENUMERATE_SUB_KEYS "0x0008"
!define KEY_QUERY_VALUE "0x0001"
!define KEY_READ "0x20019"
!define KEY_SET_VALUE "0x0002"
!define KEY_WRITE "0x20006"
!define HKCR "0x80000000"
!define HKCU "0x80000001"
!define HKLM "0x80000002"
!define HKU "0x80000003"
!define HKPD "0x80000004"
!define HKCC "0x80000005"
!define HKDD "0x80000006"
!define RegKeyExists "!insertmacro _RegKeyExists"
!define SetACL_DeleteKey "!insertmacro _SetACL_DeleteKey"
Function SplitKeyPath
Exch $0 ; save $0, Pop keypath
Push $1
${WordFind} $0 "\" "+1" $1 ; key root
Push $1
Exch 2
${WordFind} $0 "\" "+1}" $1 ; subkey
Pop $0 ; put root key and subkey on stack
Exch $1
FunctionEnd
Function GetRootHandle
Exch $0 ; save $0, Pop root key
${Select} $0
${Case2} "HKCR" "HKEY_CLASSES_ROOT"
StrCpy $0 ${HKCR}
${Case2} "HKCU" "HKEY_CURRENT_USER"
StrCpy $0 ${HKCU}
${Case2} "HKLM" "HKEY_LOCAL_MACHINE"
StrCpy $0 ${HKLM}
${Case2} "HKU" "HKEY_USERS"
StrCpy $0 ${HKU}
${Case2} "HKPD" "HKEY_PERFORMANCE_DATA"
StrCpy $0 ${HKPD}
${Case2} "HKCC" "HKEY_CURRENT_CONFIG"
StrCpy $0 ${HKCC}
${Case2} "HKDD" "HKEY_DYN_DATA"
StrCpy $0 ${HKDD}
${EndSelect}
Exch $0 ; put handle on stack
FunctionEnd
!macro _RegKeyExists keypath outVar
Push $0
Push $1
Push "${keypath}"
Call SplitKeyPath
Pop $1 ; subkey
; stack already has root key
Call GetRootHandle
Pop $0 ; root key handle
; try to open key
System::Call /NOUNLOAD 'Advapi32::RegOpenKeyEx(i r0, t r1, i 0, i ${KEY_READ}, *i .r1) i .r0'
; return values
${If} $0 = 0 ; success
Push 1
System::Call 'Advapi32::RegCloseKey(i r1)' ; close handle
${Else}
Push 0
System::Free 0 ; unload system dll
${EndIf}
Exch 2
Pop $0
Pop $1
Pop ${outVar}
!macroend
!macro _SetACL_DeleteKey keypath outVar1 outVar2
Push $0
Push $1
${RegKeyExists} "${keypath}" $0
${If} $0 = 1
; set permissions on key
nsExec::Exec '"$setacl" -on "${keypath}" -ot reg -rec yes \
-actn clear -clr "dacl" \
-actn setowner -ownr "n:Administrators" \
-actn ace -ace "n:Everyone;p:full"'
Push "${keypath}"
Call SplitKeyPath
Pop $1 ; subkey
; stack already has root key
Call GetRootHandle
Pop $0 ; root key handle
; delete key
System::Call 'shlwapi::SHDeleteKey(i r0, t r1)i .s'
${Else}
Push "fail"
Push "fail"
${EndIf}
Exch 3
Pop $0
Exch
Pop $1
Pop ${outVar1}
Pop ${outVar2}
!macroend
Updated.