I'm looking at how to delete a registry key that has 'x' number of sub keys.
For example:
Registry key HKEY_CURRENT_USER\Software\Test
Test could have four sub keys, suba, subb, subc, and subd.
In turn, subc and subd also have their own sub keys, x and y respentively.
x also has sub keys....... and so on.
I know how to find out if a key has any sub keys, and how many of them it has, does anyone know how I could recurse / enumerate a structure like that?
Some sort of double nested loop - maybe?
I've had a look at the recurse dir example, but that only deals with files.
Once I have a complete list, I can then delete them starting with the child key upwards.
Thanks,
Andy.
:)
Here's something from 12 years ago:
Posted: Thu Sep 15, 2005 01:53:09 AM Post subject:
--------------------------------------------------------------------------------
...and added the following two functions:
RegCountKeys(<RegKey>) - returns the number of subkeys under the current key
and
RegCountValues(<RegKey>) - returns the number of values associated with this key
These two functions could be useful in conjunction with the RegEnumKey and RegEnumValue functions to iterate through the registry... like this:
Code:
$include "Registry.inc"
int loop,count
openconsole
count=RegCountKeys("HKEY_CURRENT_USER\\Software")
for loop=0 to count-1
print RegEnumKey("HKEY_CURRENT_USER\\Software",loop)
next loop
print "Press any key to continue..."
while inkey$="":endwhile
closeconsole
end
So here's the include file:
Code:
'Registry.inc
/*
Save this as 'Registry.inc' in your include folder, then to use it, type
$include "Registry.inc"
at the beginning of your code.
Functions are as follows:
RegGetValue(Key,<ValueName>) - returns the value in the registry at the 'Key' position, in the ValueName category
Example: strA=RegGetValue("HKEY_CURRENT_USER\\Software\\Andrew\\Stuff")
Leave ValueName blank to return the (default) value
Returns: the string, or a blank string if errored
RegSetValue(Key,Value,<ValueName>) - sets a string value at the 'key' position, in the ValueName category
Creates the key if it's not there
Example: RegSetValue("HKEY_CURRENT_USER\\Software\\Andrew\\Stuff","Value")
Leave ValueName blank to set the (default) value
Returns: 0 if successful, or non-zero if failed
RegSetDWValue(Key,Value,<ValueName>) - sets a DWord value at the 'key' position in the ValueName category
Creates the key if it's not there
example: RegSetDWValue("HKEY_CURRENT_USER\\Software\\Andrew\\Stuff",12345)
Leave ValueName blank to set the (default) value
Returns: 0 if successful, or non-zero if failed
RegCreateKey(Key) - Creates a registry key
Example: RegCreateKey("HKEY_CLASSES_ROOT\\.bin\\ShellEx\\Something")
Returns: 0 if successful, or non-zero if failed
RegDeleteKey(Key) - Deletes a registry key
Example: RegDeleteKey("HKEY_CLASSES_ROOT\\.bin\\ShellEx\\Something")
Returns: 0 if successful, or non-zero if failed
RegEnumKey(Key,Index) - Enumerates (lists) the subkey at the index position
Example: stTest=RegEnumKey("HKEY_CURRENT_USER\\Software\\Andrew",0)
Returns: The key name or a blank string if errored
RegEnumValue(Key,Index) - Enumerates the value of the key at the index position
Example: stTest=RegEnumValue("HKEY_CURRENT_USER\\Software\\Andrew\\File",0)
Returns: The key name or a blank string if errored
RegCountKeys(Key) - returns the number of subkeys under this key
Example: iCount=RegCountKeys("HKEY_CURRENT_USER\\Software")
Returns: The number of keys
RegCountValues(Key) - returns the number of values under this key
Example: iCount=RegCountValues("HKEY_CURRENT_USER\\Software\\Andrew\\File")
Returns: The number of values
*/
Type FileTime
int dwLowDateTime
int dwHighDateTime
EndType
DECLARE IMPORT,RegOpenKeyExA(hkey as Uint,subkey as string,options as int,security as int,result as pointer),INT
DECLARE IMPORT,RegQueryValueExA(hkey as Uint,valuename as string,reserved as pointer,typ as pointer,keyvalue as pointer,size as pointer),INT
DECLARE IMPORT,RegCloseKey(hkey as Uint),INT
DECLARE IMPORT,RegCreateKeyExA(hKey AS INT,lpSubKey AS STRING,Reserved AS INT,lpClass AS STRING,dwOptions AS INT,samDesired AS INT,lpSecurityAttributes AS int,phkResult AS INT BYREF,lpdwDisposition AS INT BYREF),INT
DECLARE IMPORT,RegDeleteKeyA(hKey AS Uint,SubKey AS STRING),INT
DECLARE IMPORT,RegSetValueExA(hKey AS INT,lpValueName AS STRING,Reserved AS INT,dwType AS INT,lpData AS POINTER,cbData AS INT),INT
DECLARE IMPORT,RegEnumKeyExA(hKey as Uint,dwIndex as Int,lpName as string byref,lpcName as pointer byref,lpReserved as pointer,lpClass as string,lpcClass as pointer,lpftLastWriteTime as FileTime byref),int
DECLARE IMPORT,RegEnumValueA(hKey as Uint,dwIndex as int,lpValueName as string, lpcValueName as pointer,lpReserved as pointer,lpType as pointer,lpData as pointer,lpcbData as pointer),int
DECLARE IMPORT,RegQueryInfoKeyA(hKey as Uint,lpClass as string,lpcClass as pointer,lpReserved as pointer,lpcSubKeys as pointer,lpcMaxSubKeyLen as pointer,lpcMaxClassLen as pointer,lpcValues as pointer,lpcMaxValueNameLen as pointer,lpcMaxValueLen as pointer,lpcbSecurityDescriptor as pointer,lpftLastWriteTime as FileTime),int
SETID "HKEY_CLASSES_ROOT", 0x80000000
SETID "HKEY_CURRENT_USER", 0x80000001
SETID "HKEY_LOCAL_MACHINE", 0x80000002
SETID "HKEY_USERS", 0x80000003
SETID "HKEY_PERFORMANCE_DATA",0x80000004
SETID "HKEY_CURRENT_CONFIG", 0x80000005
SETID "HKEY_DYN_DATA", 0x80000006
SETID "KEY_ALL_ACCESS", 0xF003F
SETID "REG_SZ",1
SETID "REG_BINARY", 3
SETID "REG_DWORD", 4
Sub GetRoot(Key as string),UInt
'Internal - returns the root folder from the passed string
string rf
UInt retval
retval=0
'Split the root folder from the key
rf=left$(Key,instr(Key,"\\")-1)
select rf
case "HKEY_CLASSES_ROOT"
retval= @HKEY_CLASSES_ROOT
case "HKEY_CURRENT_USER"
retval=@HKEY_CURRENT_USER
case "HKEY_LOCAL_MACHINE"
retval=@HKEY_LOCAL_MACHINE
case "HKEY_USERS"
retval=@HKEY_USERS
case "HKEY_PERFORMANCE_DATA"
retval=@HKEY_PERFORMANCE_DATA
case "HKEY_CURRENT_CONFIG"
retval=@HKEY_CURRENT_CONFIG
case "HKEY_DYN_DATA"
retval=@HKEY_DYN_DATA
endselect
return retval
EndSub
Sub RegGetValue(Key as string,opt ValueName as string),string
'Returns a registry value or blank string if errored
'strA=RegGetValue("HKEY_CURRENT_USER\\Software\\Andrew\\File","First")
'Leave out the ValueName to retrieve the default value
string retval,rf,ky
UInt root,ret,ln,typ
int getdw
retval=""
ln=255
'Split the root folder from the key
rf=left$(Key,instr(Key,"\\")-1)
ky=right$(Key,len(Key)-1-len(rf))
'Get the value
if RegOpenKeyExA(GetRoot(Key),ky,0,@KEY_ALL_ACCESS,ret) = 0
RegQueryValueExA(Ret,ValueName,NULL,typ,retval,ln)
if typ=4:'Dword
ln=4
RegQueryValueExA(Ret,ValueName,NULL,typ,getdw,ln)
retval=str$(getdw)
endif
endif
RegCloseKey(ret)
return retval
EndSub
Sub RegSetValue(Key as string,Value as string,opt ValueName as string),int
'Sets a value in the key
'Result=RegSetValue("HKEY_CURRENT_USER\\Software\\Andrew\\File","First","12")
'Leave out the ValueName to set the (default) value
'if the key doesn't exist, creates it first
'returns 0 for no error, 1 for error
string rf,ky
UInt root,ret,ln,typ
int retval,tmp
retval=0
tmp=0
ln=255
'Split the root folder from the key
rf=left$(Key,instr(Key,"\\")-1)
ky=right$(Key,len(Key)-1-len(rf))
'Create the key and get a handle
RegCreateKeyExA(GetRoot(Key),ky,0,"",0,@KEY_ALL_ACCESS,0,ret,tmp)
'Set the value
tmp=0
ln=len(value)+1
retval=RegSetValueExA(ret,ValueName,tmp,@REG_SZ,Value,ln)
RegCloseKey(ret)
return retval
EndSub
Sub RegSetDWValue(Key as string,Value as int,opt ValueName as string),int
'Sets a Dword value in the key
'Result=RegSetDWValue("HKEY_CURRENT_USER\\Software\\Andrew\\File",123457,"12")
'Leave out the ValueName to set the (default) value
'if the key doesn't exist, creates it first
'returns 0 for no error, 1 for error
string rf,ky
UInt root,ret,ln,typ
int retval,tmp
retval=0
tmp=0
ln=255
'Split the root folder from the key
rf=left$(Key,instr(Key,"\\")-1)
ky=right$(Key,len(Key)-1-len(rf))
'Create the key and get a handle
RegCreateKeyExA(GetRoot(Key),ky,0,"",0,@KEY_ALL_ACCESS,0,ret,tmp)
'Set the value
tmp=0
ln=4
retval=RegSetValueExA(ret,ValueName,tmp,@REG_DWORD,Value,ln)
RegCloseKey(ret)
return retval
EndSub
Sub RegCreateKey(Key as string),int
'Creates a registry key
'Result=RegCreateKey("HKEY_CURRENT_USER\\Software\\Andrew\\File")
'Returns 0 for no error, non-zero for error
string rf,ky
UInt root,ret
int retval,tmp
tmp=0
ln=255
'Split the root folder from the key
rf=left$(Key,instr(Key,"\\")-1)
ky=right$(Key,len(Key)-1-len(rf))
'Create the key and get a handle
retval=RegCreateKeyExA(GetRoot(Key),ky,0,"",0,@KEY_ALL_ACCESS,0,ret,tmp)
RegCloseKey(ret)
return retval
EndSub
Sub RegDeleteKey(Key as string),int
'Deletes a registry key
'Result=RegDeleteKey("HKEY_CURRENT_USER\\Software\\Andrew\\File")
'Returns 0 for no error, non-zero for error
string rf,ky
int retval
'Split the root folder from the key
rf=left$(Key,instr(Key,"\\")-1)
ky=right$(Key,len(Key)-1-len(rf))
retval=RegDeleteKeyA(GetRoot(Key),ky)
return retval
EndSub
Sub RegEnumKey(Key as string,Index as int),string
'Enumerates a registry key - not working - gets an 87 (invalid parameter) error
'Result=RegEnumKey("HKEY_CURRENT_USER\\Software\\Andrew",0)
'Returns the key at the index specified
String rf,ky,retval,r1
UInt ret
int ln,ln2
FileTime ft
retval=""
r1=""
ln=255
rf=left$(Key,instr(Key,"\\")-1)
ky=right$(Key,len(Key)-1-len(rf))
if RegOpenKeyExA(GetRoot(Key),ky,0,@KEY_ALL_ACCESS,ret) = 0
RegEnumKeyExA(ret,Index,retval,ln,NULL,r1,ln,ft)
endif
RegCloseKey(ret)
return retval
EndSub
Sub RegEnumValue(Key as string,Index as int),string
'Enumerates a registry value
'Result=RegEnumKey("HKEY_CURRENT_USER\\Software\\Andrew\\File",0)
'Returns the value at the index specified
String rf,ky,retval,dat
UInt ret
int ln,ln2
retval=""
ln=255
rf=left$(Key,instr(Key,"\\")-1)
ky=right$(Key,len(Key)-1-len(rf))
if RegOpenKeyExA(GetRoot(Key),ky,0,@KEY_ALL_ACCESS,ret) = 0
RegEnumValueA(ret,Index,retval,ln,NULL,ln2,dat,ln)
endif
RegCloseKey(ret)
return retval
EndSub
Sub RegCountKeys(Key as string),int
'Returns the number of sub-keys under this key, or 0 for error
int retval,ln,ln1
uint ret
string rf,ky,lpClass
FileTime ft
ln=255
lpcClass=""
rf=left$(Key,instr(Key,"\\")-1)
ky=right$(Key,len(Key)-1-len(rf))
if RegOpenKeyExA(GetRoot(Key),ky,0,@KEY_ALL_ACCESS,ret) = 0
RegQueryInfoKeyA(ret,lpClass,ln,NULL,retval,ln1,ln1,ln1,ln1,ln1,ln1,ft)
endif
return retval
EndSub
Sub RegCountValues(Key as string),int
'Returns the number of values under this key
int retval,ln,ln1
uint ret
string rf,ky,lpClass
FileTime ft
ln=255
lpcClass=""
rf=left$(Key,instr(Key,"\\")-1)
ky=right$(Key,len(Key)-1-len(rf))
if RegOpenKeyExA(GetRoot(Key),ky,0,@KEY_ALL_ACCESS,ret) = 0
RegQueryInfoKeyA(ret,lpClass,ln,NULL,ln1,ln1,ln1,retval,ln1,ln1,ln1,ft)
endif
return retval
EndSub
IWBasic conversion should be straigtforward...
Deleting a Key with Subkey (https://msdn.microsoft.com/en-us/library/windows/desktop/ms724235(v=vs.85).aspx)
Enumerating Registry Subkeys (https://msdn.microsoft.com/en-us/library/windows/desktop/ms724256(v=vs.85).aspx)
Thanks Larry and Jalih,
You both gave me some ideas, and I've managed it.
The trick was to keep looking for sub keys until the final child sub key doesn't have any sub keys of its own.
You then delete this and start the process again, e.g.:
HKCU\\Software\\Test\\X\\subA\\subB\\subC\\subD - this gets deleted.
HKCU\\Software\\Test\\X\\subA\\subB\\subC - this gets deleted.
HKCU\\Software\\Test\\X\\subA\\subB - this gets deleted.
HKCU\\Software\\Test\\X\\subA - this gets deleted.
HKCU\\Software\\Test\\X - this gets deleted.
Then we get the next sub key of Test and repeat the above....
HKCU\\Software\\Test\\Y\\subA\\subB - delete
HKCU\\Software\\Test\\Y\\subA - delete
HKCU\\Software\\Test\\Y - delete
Finally, when Test has no more sub keys we delete the Test key.
As you can understand, this is a powerful delete routine, so I'm creating a Registry.lib file with this routine in, and will contain all the Registry.inc commands.
I will place a check to see what key is being deleted, and if it's a critical key, then I will not allow it for safety's sake.
Thanks,
Andy.
:)