Help with calling the registry

Hi all,
Hope someone can help me as I’m tearing my hair out here!

I’m trying to call the registry to read HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProductId.
The problem is that this is redirected by Windows by the registry redirector, and Xojo does not have the ability to read the 64 bit registry view natively.

I’ve tried coding this workaround by calling the dll directly but it’s not working. Can anyone help? Thankyou :slight_smile:

Declare Function RegOpenKeyEx Lib “advapi32.dll” Alias “RegOpenKeyExA” (hKey As Integer, lpSubKey As CString, ulOptions As Integer, samDesired As Integer, ByRef phkResult As Integer) As Integer
Declare Function RegQueryValueExString Lib “advapi32.dll” Alias “RegQueryValueExA” (ByVal hKey As integer, ByVal lpValueName As CString, ByVal lpReserved As integer, lpType As integer, ByRef lpData As Cstring, lpcbData As integer) As integer

Const HKEY_LOCAL_MACHINE = &H80000002
Const KEY_QUERY_VALUE = &H1
Const REG_SZ = &H1
Const KEY_WOW64_64KEY = &H100
Const KEY_WOW64_32KEY = &H200
Const KEY_READ = &H20019
Const KEY_ALL_ACCESS = &HF003F

dim lResult As Integer
dim lHandle As Integer
dim slength as integer
dim retval as integer
dim hregkey as integer
dim i as double
dim stringbuffer as CString

lResult =RegOpenKeyEx(HKEY_LOCAL_MACHINE,“SOFTWARE\Microsoft\Windows NT\CurrentVersion”, 0,KEY_WOW64_64KEY, lHandle)

for i = 1 to 255
stringbuffer = stringbuffer + " "
next i
slength = 255
retval = RegQueryValueExString(lHandle, “ProductId”, &H0, REG_SZ, stringbuffer, slength)
stringbuffer = Left(stringbuffer, slength)

msgbox cstr(stringbuffer)

I can get this working on Win.XP and it does work on Win.7 if I right-click my .exe and select run as administrator -
I have changed any API integer values to int32 ( cosmetic right now, but more future proof ) but my code so far is…

Soft Declare Function RegOpenKeyEx Lib “advapi32.dll” Alias “RegOpenKeyExA” ( _
ByVal hKey As Int32, _
lpSubKey As CString, _
ByVal ulOptions As Int32, _
ByVal samDesired As Int32, _
ByRef phkResult As Int32 _
) As Integer

Soft Declare Function RegQueryValueExString Lib “advapi32.dll” Alias “RegQueryValueExA” ( _
ByVal hKey As int32, _
lpValueName As CString, _
ByVal lpReserved As int32, _
ByRef lpType As int32, _
lpData As Cstring, _
ByRef lpcbData As int32 _
) As integer

soft Declare Function RegCloseKey Lib “advapi32.dll” Alias “RegCloseKey” ( ByVal hKey As int32 ) As integer

Const HKEY_LOCAL_MACHINE = &H80000002
Const KEY_QUERY_VALUE = &H1
Const REG_SZ = &H1
Const KEY_WOW64_64KEY = &H100
Const KEY_WOW64_32KEY = &H200
Const KEY_READ = &H20019
Const ERROR_SUCCESS = 0

dim intLoop as integer
dim lngResult As Int32
dim lngHandle As Int32
dim lngValueLength as int32
dim lngRegType as int32
dim lngSam as integer
dim strRegKey as string

dim cstrValue as CString
dim strValue as string

// I output messages to a textarea on my form, so clear it…
self.txtMsg.text = “”

// Get handle to reg key…

strRegKey = “SOFTWARE\Microsoft\Windows NT\CurrentVersion”
lngSam = KEY_READ + KEY_WOW64_64KEY

lngResult =RegOpenKeyEx(HKEY_LOCAL_MACHINE, strRegKey, 0, lngSam, lngHandle)

if lngResult <> ERROR_SUCCESS then
self.txtMsg.text = "OpenKey failed, code: " + str( lngResult )
RETURN
end if

self.txtMsg.text = "Got handle: " + str( lngHandle )
self.txtMsg.Refresh

// Get string length…

lngResult = RegQueryValueExString(lngHandle, “ProductId”, &H0, lngRegType, nil, lngValueLength)
if lngResult <> ERROR_SUCCESS then
self.txtMsg.text = self.txtMsg.text + endofline + "Query Value length failed, code: " + str( lngResult )
RETURN
end if

if lngRegType <> REG_SZ then
self.txtMsg.text = self.txtMsg.text + endofline + "Not REG_SZ type: " + str( lngRegType )
RETURN
end if

self.txtMsg.text = self.txtMsg.text + endofline + "GOT Length: " + str( lngValueLength )
self.txtMsg.Refresh

// Add one to value length to ensure room for Cstring terminator…
lngValueLength = lngValueLength + 1

// Get string…
for intLoop = 1 to lngValueLength
cstrValue = cstrValue + " "
next intLoop

lngResult = RegQueryValueExString(lngHandle, “ProductId”, &H0, lngRegType, cstrValue, lngValueLength)
if lngResult <> ERROR_SUCCESS then
self.txtMsg.text = self.txtMsg.text + endofline + "Query Value failed, code: " + str( lngResult )
RETURN
end if

self.txtMsg.text = self.txtMsg.text + endofline + "GOT STRING: Length: " + str( lngValueLength )
self.txtMsg.Refresh

cstrValue = Left(cstrValue, lngValueLength)

self.txtMsg.text = self.txtMsg.text + endofline + “Value:” + cstr(cstrValue)

// Close key
lngResult = RegCloseKey( lngHandle )
if lngResult <> ERROR_SUCCESS then
self.txtMsg.text = self.txtMsg.text + endofline + "Close key failed, code: " + str( lngResult )
RETURN
end if

RETURN


Hope it helps

Hi Chris
Yes, thankyou. This is exactly that I was looking for.
Its a pity that Xojo doesn’t support this natively, 64 bit is very mainstream!

Glad to have been of some help. I just happened to be coding those same registry calls in c that day and it was useful to do the Xojo version as well at the same time.

I agree it would be useful if Xojo were to implent something like a .Use64bit boolean property, defaulting to false until they can provide the option of producing 64 bit .exe files. I am a little shy of putting a feedback request for this because:-

  1. My guess is that they are well aware of this issue and it will need adressing for the 64bit .exe work anyway.
  2. There is the workaround of doing what I / we have.
  3. They have enough on their plate right now !