RegOp Class for 64-bit VBA
Updating a classic VBA registry reading and writing class module for 64-bit compatibility.
For years I've used the RegOp class from Romke Soldaat to access the Windows registry when I wanted something more complicated than the GetSetting and SaveSetting methods.
Unfortunately, like most VBA code posted to the internet during the glory days of VB6 development (late '90s to early '00s), the code is not compatible with 64-bit VBA.
Following Philipp Stiefel's excellent guidance, I updated the API declarations for 64-bit compatibility.
I've listed the updated API declarations below. You'll need to copy and paste the listing from Romke's article into a new class module, then overwrite his API declarations with the code below for all that 64-bit goodness (be sure to read the important UPDATEs at the bottom of the article after the API declaration code):
#If VBA7 Then
Private Type SECURITY_ATTRIBUTES
nLength As Long
lpSecurityDescriptor As LongPtr
bInheritHandle As Long
End Type
#Else
Private Type SECURITY_ATTRIBUTES
nLength As Long
lpSecurityDescriptor As Long
bInheritHandle As Long
End Type
#End If
' RegCreateKeyEx creates the specified key. If the key
' already exists, the function opens it. The phkResult
' parameter receives the key handle.
#If VBA7 Then
Private Declare PtrSafe Function RegCreateKeyEx _
Lib "advapi32.dll" Alias "RegCreateKeyExA" ( _
ByVal hKey As LongPtr, ByVal lpSubKey As String, _
ByVal Reserved As Long, ByVal lpClass As String, _
ByVal dwOptions As Long, ByVal samDesired As Long, _
lpSecurityAttributes As SECURITY_ATTRIBUTES, _
phkResult As LongPtr, lpdwDisposition As Long) As Long
#Else
Private Declare Function RegCreateKeyEx _
Lib "advapi32.dll" Alias "RegCreateKeyExA" ( _
ByVal hKey As Long, ByVal lpSubKey As String, _
ByVal Reserved As Long, ByVal lpClass As String, _
ByVal dwOptions As Long, ByVal samDesired As Long, _
lpSecurityAttributes As SECURITY_ATTRIBUTES, _
phkResult As Long, lpdwDisposition As Long) As Long
#End If
'RegCloseKey releases a handle to the specified key.
'(Key handles should not be left open any longer than
'necessary.)
#If VBA7 Then
Private Declare PtrSafe Function RegCloseKey Lib "advapi32.dll" ( _
ByVal hKey As LongPtr) As Long
#Else
Private Declare Function RegCloseKey Lib "advapi32.dll" ( _
ByVal hCurKey As Long) As Long
#End If
' RegQueryInfoKey retrieves information about the specified
'key, such as the number of subkeys and values, the length
'of the longest value and key name, and the size of the
'longest data component among the key's values.
#If VBA7 Then
Private Declare PtrSafe Function RegQueryInfoKey _
Lib "advapi32.dll" Alias "RegQueryInfoKeyA" ( _
ByVal hKey As LongPtr, ByVal lpClass As String, _
lpcbClass As Long, ByVal lpReserved As LongPtr, _
lpcSubKeys As Long, lpcbMaxSubKeyLen As Long, _
lpcbMaxClassLen As Long, lpcValues As Long, _
lpcbMaxValueNameLen As Long, lpcbMaxValueLen As Long, _
lpcbSecurityDescriptor As Long, _
lpftLastWriteTime As Long) As Long
#Else
Private Declare Function RegQueryInfoKey _
Lib "advapi32.dll" Alias "RegQueryInfoKeyA" ( _
ByVal hCurKey As Long, ByVal lpClass As String, _
lpcbClass As Long, ByVal lpReserved As Long, _
lpcSubKeys As Long, lpcbMaxSubKeyLen As Long, _
lpcbMaxClassLen As Long, lpcValues As Long, _
lpcbMaxValueNameLen As Long, lpcbMaxValueLen As Long, _
lpcbSecurityDescriptor As Long, _
lpftLastWriteTime As Long) As Long
#End If
'RegEnumKeyEx enumerates subkeys of the specified open
'key. Retrieves the name (and its length) of each subkey.
#If VBA7 Then
Private Declare PtrSafe Function RegEnumKeyEx Lib "advapi32.dll" _
Alias "RegEnumKeyExA" (ByVal hKey As LongPtr, _
ByVal dwIndex As Long, ByVal lpName As String, _
lpcbName As Long, ByVal lpReserved As LongPtr, _
ByVal lpClass As String, lpcbClass As Long, _
lpftLastWriteTime As Long) As Long
#Else
Private Declare Function RegEnumKeyEx Lib "advapi32.dll" _
Alias "RegEnumKeyExA" (ByVal hCurKey As Long, _
ByVal dwIndex As Long, ByVal lpName As String, _
lpcbName As Long, ByVal lpReserved As Long, _
ByVal lpClass As String, lpcbClass As Long, _
lpftLastWriteTime As Long) As Long
#End If
'RegEnumValue enumerates the values for the specified open
'key. Retrieves the name (and its length) of each value,
'and the type, content and size of the data.
#If VBA7 Then
Private Declare PtrSafe Function RegEnumValue Lib "advapi32.dll" _
Alias "RegEnumValueA" (ByVal hKey As LongPtr, _
ByVal dwIndex As Long, ByVal lpValueName As String, _
lpcbValueName As Long, ByVal lpReserved As LongPtr, _
lpType As Long, lpData As Any, lpcbData As Long) As Long
#Else
Private Declare Function RegEnumValue Lib "advapi32.dll" _
Alias "RegEnumValueA" (ByVal hCurKey As Long, _
ByVal dwIndex As Long, ByVal lpValueName As String, _
lpcbValueName As Long, ByVal lpReserved As Long, _
lpType As Long, lpData As Any, lpcbData As Long) As Long
#End If
'RegQueryValueEx retrieves the type, content and data for
' a specified value name. Note that if you declare the
' lpData parameter as String, you must pass it By Value.
#If VBA7 Then
Private Declare PtrSafe Function RegQueryValueEx _
Lib "advapi32.dll" Alias "RegQueryValueExA" ( _
ByVal hKey As LongPtr, ByVal lpValueName As String, _
ByVal lpReserved As LongPtr, lpType As Long, _
lpData As Any, lpcbData As Long) As Long
#Else
Private Declare Function RegQueryValueEx _
Lib "advapi32.dll" Alias "RegQueryValueExA" ( _
ByVal hCurKey As Long, ByVal lpValueName As String, _
ByVal lpReserved As Long, lpType As Long, _
lpData As Any, lpcbData As Long) As Long
#End If
'RegSetValueEx sets the data and type of a specified
' value under a key.
' Note that if you declare the lpData parameter as String, you must pass it By Value.
#If VBA7 Then
Private Declare PtrSafe Function RegSetValueEx Lib "advapi32.dll" _
Alias "RegSetValueExA" (ByVal hKey As LongPtr, _
ByVal lpValueName As String, ByVal Reserved As Long, _
ByVal dwType As Long, lpData As Any, _
ByVal cbData As Long) As Long
#Else
Private Declare Function RegSetValueEx Lib "advapi32.dll" _
Alias "RegSetValueExA" (ByVal hCurKey As Long, _
ByVal lpValueName As String, ByVal Reserved As Long, _
ByVal dwType As Long, lpData As Any, _
ByVal cbData As Long) As Long
#End If
'RegDeleteValue removes a named value from specified key.
#If VBA7 Then
Private Declare PtrSafe Function RegDeleteValue _
Lib "advapi32.dll" Alias "RegDeleteValueA" ( _
ByVal hKey As LongPtr, ByVal lpValueName As String) As Long
#Else
Private Declare Function RegDeleteValue _
Lib "advapi32.dll" Alias "RegDeleteValueA" ( _
ByVal hCurKey As Long, ByVal lpValueName As String) As Long
#End If
'RegDeleteKey deletes a subkey. Under Win 95/98, also
'deletes all subkeys and values. Under Windows NT/2000,
'the subkey to be deleted must not have subkeys. The class
'attempts to use SHDeleteKey (see below) before using
'RegDeleteKey.
#If VBA7 Then
Private Declare PtrSafe Function RegDeleteKey Lib "advapi32.dll" _
Alias "RegDeleteKeyA" (ByVal hKey As LongPtr, _
ByVal lpSubKey As String) As Long
#Else
Private Declare Function RegDeleteKey Lib "advapi32.dll" _
Alias "RegDeleteKeyA" (ByVal hKey As Long, _
ByVal lpSubKey As String) As Long
#End If
'SHDeleteKey deletes a subkey and all its descendants.
'Under Windows NT 4.0, Internet Explorer 4.0 or later
'is required.
#If VBA7 Then ' Not Found in Win32API_PtrSafe.TXT
Private Declare PtrSafe Function SHDeleteKey Lib "Shlwapi" _
Alias "SHDeleteKeyA" (ByVal hKey As LongPtr, _
ByVal lpSubKey As String) As Long
#Else
Private Declare Function SHDeleteKey Lib "Shlwapi" _
Alias "SHDeleteKeyA" (ByVal hKey As Long, _
ByVal lpSubKey As String) As Long
#End If
#If VBA7 Then
Private Declare PtrSafe Function LoadLibrary Lib "kernel32" _
Alias "LoadLibraryA" (ByVal lpLibFileName As String) As LongPtr
#Else
Private Declare Function LoadLibrary Lib "kernel32" _
Alias "LoadLibraryA" (ByVal lpLibFileName As String) As Long
#End If
#If VBA7 Then
Private Declare PtrSafe Function FreeLibrary Lib "kernel32" (ByVal hLibModule As LongPtr) As Long
#Else
Private Declare Function FreeLibrary Lib "kernel32" (ByVal hLibModule As Long) As Long
#End If
#If VBA7 Then
Private Declare PtrSafe Function ExpandEnvStrings Lib "kernel32" _
Alias "ExpandEnvironmentStringsA" ( _
ByVal lpSrc As String, ByVal lpDst As String, _
ByVal nSize As Long) As Long
#Else
Private Declare Function ExpandEnvStrings Lib "kernel32" _
Alias "ExpandEnvironmentStringsA" ( _
ByVal lpSrc As String, ByVal lpDst As String, _
ByVal nSize As Long) As Long
#End If
#If VBA7 Then
Private Declare PtrSafe Function GetVersionEx Lib "kernel32" _
Alias "GetVersionExA" ( _
lpVersionInformation As OSVERSIONINFO) As Long
#Else
Private Declare Function GetVersionEx Lib "kernel32" _
Alias "GetVersionExA" ( _
lpVersionInformation As OSVERSIONINFO) As Long
#End If
Final Steps to Get the Code to Compile
Step 1. Replace hCurKey
Declaration
UPDATE [2022-01-10]: You will also need to replace the following module-level declaration:
Private hCurKey
With this code:
#If VBA7 Then
Private hCurKey As LongPtr
#Else
Private hCurKey As Long
#End If
For more details, see here:
Step 2. Replace hLib
Declaration
UPDATE [2022-01-12]: Additionally, you will need to replace the following code in Function ShlwapiInstalled
:
Dim hLib As Variant
With this code:
#If VBA7 Then
Dim hLib As LongPtr
#Else
Dim hLib As Long
#End If
Special thanks to former Access MVP Tom Wickerath for reporting these two issues.