Reading and Writing Registry Keys with Visual Basic
Pages: 1, 2, 3
Getting Information about Keys
Once you've opened a key, you sometimes know what subkeys and values it contains. In other cases, you may not be completely sure about its keys and values. And sometimes, you have absolutely no idea what its subkeys and their values are. To help you handle situations in which you don't know the number and names of subkeys, you can call the RegQueryInfoKey function. Its syntax is:
Public Declare Function RegQueryInfoKey Lib "advapi32.dll" Alias "RegQueryInfoKeyA" _
(ByVal hKey As Long, _ ' Handle of key to query
ByVal lpClass As String, _ ' Class (unsued except for remote keys)
lpcbClass As Long, _ ' Length of class string (unused)
ByVal lpReserved As Long, _ ' Reserved, must be 0
lpcSubKeys As Long, _ ' Number of subkeys
lpcbMaxSubKeyLen As Long, _ ' Length of longest subkey name
lpcbMaxClassLen As Long, _ ' Length of longest class name (unused)
lpcValues As Long, _ ' Number of values
lpcbMaxValueNameLen As Long, _ ' Length of longest value name
lpcbMaxValueLen As Long, _ ' Length of longest value
lpcbSecurityDescriptor As Long, _ ' Security Descriptor
lpftLastWriteTime As FILETIME _ ' Date/time of last write to key
) As Long
Note that most of these arguments are passed to the function by reference; that is, on return, their values are updated to reflect the results of the query. RegQueryInfoKey provides us with the following items of information:
The number of subkeys. With this information, we can enumerate subkeys using the
RegEnumKeyfunction.The greatest number of characters in a subkey name. With this information, we can allocate a large enough buffer when calling
RegEnumKeyto retrieve the complete name of each subkey. Each of these subkeys can then be opened using theRegOpenKeyExfunction.The number of values. With this information, we can enumerate values using the
RegEnumValuefunction.The greatest number of characters in a named value. With this information, we can allocate a sufficiently large buffer when calling
RegEnumValueto retrieve the complete name of each value.The greatest number of bytes in a value. With this information, we can allocate a large enough buffer when calling
RegQueryValueExto retrieve all the data belonging to each value.
Once you know the number of subkeys belonging to an open key, you can iterate them using the RegEnumKeyEx function. Its syntax is:
Public Declare Function RegEnumKeyEx Lib "advapi32.dll" Alias "RegEnumKeyExA" _
(ByVal hKey As Long, _ ' Handle of open key
ByVal dwIndex As Long, _ ' Index of subkey
ByVal lpName As String, _ ' Name of key
lpcbName As Long, _ ' Length of name buffer
ByVal lpReserved As Long, _ ' Reserved, must be 0
ByVal lpClass As String, _ ' Class name (usually usused)
lpcbClass As Long, _ ' Length of class name
lpftLastWriteTime As FILETIME _ ' Date of last write
) As Long
The following code illustrates the use of RegQueryInfoKey, RegEnumKeyEx, and RegOpenKeyEx to open each of the subkeys of HKEY_CURRENT_USER\Control Panel:
Dim lResult As Long
Dim hKey As Long
Dim lNumKeys As Long ' Number of subkeys of open key
Dim lSubkeyNameLen As Long ' Length of the longest subkey name
Dim ft As FILETIME
Dim sRegPath As String
Dim sa As SECURITY_ATTRIBUTES ' Use default security attributes of process
sa.nLength = Len(sa)
sa.bInheritHandle = CLng(True)
If RegOpenKeyEx(HKEY_CURRENT_USER, "Control Panel", 0, KEY_READ, hKey) = ERROR_SUCCESS Then
' Get subkey information
lResult = RegQueryInfoKey(hKey, vbNullString, 0, 0, lNumKeys, lSubkeyNameLen, _
0, 0, 0, 0, 0, ft)
If lResult = ERROR_SUCCESS Then
Dim sMsg As String
sMsg = "Key: HKEY_CURRENT_USER\Control Panel" & vbCrLf & vbCrLf
sMsg = sMsg & "Subkeys: " & lNumKeys & vbCrLf
sMsg = sMsg & "Longest subkey name: " & lSubkeyNameLen & vbCrLf
MsgBox sMsg
End If
' Use subkey information to enumerate subkeys
Dim lCtr As Long
Dim sBuffer As String
Dim lBuffer As Long
Dim hSubkey As Long
' Loop as many times as there are subkeys
For lCtr = 0 To lNumKeys - 1
' Initialize buffer to hold name to be 1 greater than maximum length
sBuffer = Space(lSubkeyNameLen) & Chr(0)
lBuffer = Len(sBuffer)
RegEnumKeyEx hKey, lCtr, sBuffer, lBuffer, 0, vbNullString, 0, ft
' Trim returned buffer to extract key name
sBuffer = Left(sBuffer, lBuffer)
sMsg = "Key " & lCtr & ": " & sBuffer & vbCrLf
' Open subkey
RegOpenKeyEx hKey, sBuffer, 0, KEY_READ, hSubkey
sMsg = sMsg & " Returned handle " & Hex(hSubkey) & vbCrLf
MsgBox sMsg
RegCloseKey hSubkey
Next
RegCloseKey hKey
Else
MsgBox "Unable to open key: " & lResult
End If
Note that the code calls RegQueryInfoKey to determine the total number of subkeys and the number of characters in the longest subkey name. Since we're not interested in any of the other information that the function is able to retrieve, we simply provide default literal values (0 for Longs, the vbNullString constant for Strings) in place of the arguments we don't care about.
The loop that repeatedly calls RegEnumKeyEx has a starting index value of 0 and a maximum value of 1 less than the total number of subkeys. Failing to begin the loop at 0 will cause an error. For each call to RegEnumKeyEx, we initialize a buffer whose length is one greater than the maximum number of characters in a subkey name; this allows for the full subkey name to be written to the buffer, along with a terminating null character (or Chr(0)). When RegEnumKeyEx returns, lBuffer is updated to reflect the actual number of characters in the subkey name without the terminating null character. The call to the intrinsic VB Left function discards any portion of the string that is unnecessary. Once we have extracted the name of the subkey, we can call RegOpenKeyEx to open that key.
Deleting a Registry Key
Deleting a registry key would appear to be a straightforward matter: you just call the RegDeleteKey function, whose syntax is:
Public Declare Function RegDeleteKey Lib "advapi32.dll" Alias "RegDeleteKeyA" _
(ByVal hKey As Long, _ ' Handle of open key
ByVal lpSubKey As String _ ' Path from handle to key
) As Long
Here, hKey is a handle to an open key, and lpSubKey is a string containing the path to the subkey to be deleted. Since the second parameter cannot be a null string, the function requires that you delete a subkey of an open key. The complication, however, is that on Windows NT/2000/XP systems, the function fails if the subkey to be deleted itself contains any subkeys.
You can work around this problem in either of two ways:
- You can write code that uses recursion to iterate each of the child keys belonging to the key that you'd like to delete.
- You can call the Windows Shell library's
SHDeleteKeyfunction, which iterates and deletes the child keys before deleting the key itself.
Since relying on operating system services rather than writing code that duplicates system services is sound practice, calling SHDeleteKey is far preferable to writing your own code. The syntax of SHDeleteKey is:
Public Declare Function SHDeleteKey Lib "shlwapi.dll" Alias "SHDeleteKeyA" _
(ByVal hKey As Long, ByVal pszSubKey As String) As Long
You could then delete the HKEY_CURRENT_USER\Software\MyCompany\MyCorporateApp key and its child keys with the following code:
Dim lResult As Long
Dim hKey As Long
If RegOpenKeyEx(HKEY_CURRENT_USER, "Software", 0, KEY_ALL_ACCESS, hKey) = ERROR_SUCCESS Then
lResult = SHDeleteKey(hKey, "MyCompany")
RegCloseKey hKey
End If
Ron Petrusha is the author and coauthor of many books, including "VBScript in a Nutshell."
Return to WindowsDevCenter.com.

