March 28, 2024, 02:39:24 AM

News:

Own IWBasic 2.x ? -----> Get your free upgrade to 3.x now.........


recurse registry sub keys

Started by Andy, July 19, 2017, 07:49:06 AM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Andy

July 19, 2017, 07:49:06 AM Last Edit: July 19, 2017, 07:53:11 AM by Andy
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.
:)   
Day after day, day after day, we struck nor breath nor motion, as idle as a painted ship upon a painted ocean.

LarryMc

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


LarryMc
Larry McCaughn :)
Author of IWB+, Custom Button Designer library, Custom Chart Designer library, Snippet Manager, IWGrid control library, LM_Image control library

jalih

July 19, 2017, 08:53:49 AM #2 Last Edit: July 19, 2017, 08:55:52 AM by jalih
IWBasic conversion should be straigtforward...

Deleting a Key with Subkey
Enumerating Registry Subkeys

Andy

July 20, 2017, 12:01:34 AM #3 Last Edit: July 20, 2017, 12:05:01 AM by Andy
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.
:)
Day after day, day after day, we struck nor breath nor motion, as idle as a painted ship upon a painted ocean.