Read Registry Windows

Hi,
I’m new to Xojo so would appreciate some help with figuring out what’s going wrong here.
I’m having issues with reading the registry specifically in obtaining information from OEMInformation and obtaining the install date.

Currently I’m using this code to obtain the install date on the system:

Dim sysdate As New RegistryItem("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", False)
Dim systemdate As String = sysdate.Value("InstallDate")
DateDisplay.text = systemdate

However this only shows 0 which is incorrect. I’m trying to get it to show the date which I understand will need to be converted from unix time however its just showing 0 as of now.

My second issue is with obtaining the OEMInformation, I’ve used a similar code to above except I’m obtaining from: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\OEMInformation and I’m getting the values of Manufacturer and Model and outputting to a multi-line label, the problem with this is I’m getting no output whatsoever, it’s just blank.

Thanks.

If you open RegEdit (hit start menu, type “RegEdit”) and naviate to HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion you will see that InstallDate is a REG_DWORD - in Microsoft speak, DWORDs are UINT32s (Note: this is true even in a 64 bit OS).
I believe that this is the # of seconds since 1970. But Xojo dates are 1904-based - so your code could changed as follows:

Dim sysdate As New RegistryItem("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", False)
Dim secondsSince1970 As Uint32 = sysdate.Value("InstallDate")

// convert from 1970 to 1904-based date by calculating the offset
dim d1970 as new date
d1970.year = 1970
dim d1904 as new date
d1904.year = 1904

dim secondsBetween1904and1970 as double = d1970.totalSeconds - d1904.totalSeconds

// now, create our date
dim systemdate as new date 
systemdate.totalSeconds = secondsSince1970 + secondsBetween1904and1970
DateDisplay.text = systemdate.sqlDateTime

This gives me an output to DateDisplay of 1970-01-01?

That would indicate that you are not reading anything from the Registry. All you have is the date adjustment. The InstallDate key that you are looking for is not there.

As suggested earlier, use Regedit to find precisely where the target key is located on 32-bit and on 64-bit Windows.

I’m reading from the correct registry location, I can see from registry that it has a value in it of “5b69d681”

Would running the program from IDE rather than building be having an affect?

have you tried to convert the hexadecimal value to a decimal value before calculating the date? Your hex value corresponds to 1533662849. I bet that this value will work in your code.

look at this doc page.

You won’t see any value if you run a 32bit app in a 64bit OS because the registry call for

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion

will be looking in a different location

HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows NT\CurrentVersion)

which actually has a 0 for InstallDate in that location.

If you use Michael’s code then change the app to compile for 64bit it’ll work.

To do that, just scroll to the bottom of the left navigator where you will see a check mark next to This Computer. Click that then in the right nav (click the inspector button if this isn’t open) select the architecture drop down and click x86 64-bit.

Now try running your program and you should see the expected value.

If you don’t want to compile for 64bit and still want to read out of the 32bit portion of the registry, you’ll need to implement your own registry reading calls using Declares.

That’s fixed all my problems switching it to 64bit. Thanks.

I recently ran into a problem where I couldn’t read or write to the registry on some Windows computers - especially new ones, or older ones that had their hard drives replaced.

What I found (via an online article) was that some (but not all) Windows Vista installs and later, use Registry Virtualization.

So I wound up using this code:

Dim RegistrySource as String
Dim Reg as RegistryItem

If SystemInformationMBS.IsWindowsVista(True) then // Vista or newer

 RegistrySource = "HKEY_CURRENT_USER\\Software\\Classes\\VirtualStore\\MACHINE\\SOFTWARE\\McKernon\\Lightwright6\\Regis"

Else

 RegistrySource = "HKEY_LOCAL_MACHINE\\Software\\McKernon\\Lightwright6\\Regis"

End If

Reg = New RegistryItem(RegistrySource)

Does anyone see problems using this method? Or should I switch to using WOW6432Node?

I wouldn’t continue down that route John. You’re essentially trying to store your application settings in the wrong place.

HKEY_LOCAL_MACHINE\Software should be used to store infrequent machine specific information, settings for services etc. You won’t have access to this area until the user passes a UAC check or is an administrator.

HKEY_CURRENT_USER\Software should be used to store setting for a logged in user and their installed applications. The user doesn’t need any special permissions to write here. These settings will move with the user between machine if they are in a multi user environment or use online profiles or whatever its called this week :wink:

VirtualStore is just a stop gap to bridge the migration of pre-vista apps to more modern OS’s and shouldn’t be used past that remit. It is essentially proving a “fake” place to store those HKEY_LOCAL_MACHINE settings inside the users writable HKEY_CURRENT_USER area, so older apps won’t instantly break or have access issues during migration.

See here for more info: https://en.wikipedia.org/wiki/Windows_Registry and https://docs.microsoft.com/en-us/windows/desktop/sysinfo/registry

[quote=422041:@]HKEY_LOCAL_MACHINE\Software should be used to store infrequent machine specific information, settings for services etc. You won’t have access to this area until the user passes a UAC check or is an administrator.

HKEY_CURRENT_USER\Software should be used to store setting for a logged in user and their installed applications. The user doesn’t need any special permissions to write here. These settings will move with the user between machine if they are in a multi user environment or use online profiles or whatever its called this week :wink:

[/quote]

I’m trying to store settings that all users on the computer need access to, that’s why it’s LOCAL_MACHINE.

Suggestions?

Ah, in that case you could do one of the following:

  1. Take care of it all during install when the installer does the elevation
  2. Elevate the app so the UAC pops up. This can be done a few ways:

a) Have your program be able to start with command line params that just starts, performs the registry tweaks then closes down without showing any UI. This allows you to use the same app for elevated registry tweaks rather than two apps as with b) below
b) Have another small app that takes care of your registry tweaks. Call that via elevation from the first to take care of the registry tweaks.

Here’s some code from an old test project of mine (probably needs some prettifying) that will try an elevate.

[code]Public Function RunAs(filename As String, ParamArray Parameters As String) as Integer
'Declares created using https://forum.xojo.com/47389-xojo-ide-reformat-code-script or https://blog./2017/01/22/windows-to-xojo-data-type-conversion/

'See https://msdn.microsoft.com/en-us/library/windows/desktop/bb762153(v=vs.85).aspx for more error messages and flags
'More info at https://docs.microsoft.com/en-gb/windows/desktop/api/shellapi/ns-shellapi-_shellexecuteinfoa

'I have added all the error messages here so you can add extra functionality if you require it
Const SE_ERR_FNF = 2 'file not found
Const SE_ERR_PNF = 3 'path not found
Const SE_ERR_ACCESSDENIED = 5 'access denied
Const SE_ERR_OOM = 8 'out of memory
Const SE_ERR_SHARE = 26 'Cannot share an open file
Const SE_ERR_ASSOCINCOMPLETE = 27 'File association information not complete
Const SE_ERR_DDETIMEOUT = 28 'DDE operation timed out
Const SE_ERR_DDEFAIL = 29 'DDE operation failed
Const SE_ERR_DDEBUSY = 30 'DDE operation is busy
Const SE_ERR_NOASSOC = 31 'File association not available
Const SE_ERR_DLLNOTFOUND = 32 'Dynamic-link library not found

'flags - See https://docs.microsoft.com/en-gb/windows/desktop/api/shellapi/nf-shellapi-shellexecutea
Const SW_HIDE = 0
Const SW_SHOWNORMAL = 1

Dim ok As Integer
Dim params As String = Join(Parameters, " ")

Soft Declare Function ShellExecute Lib “Shell32” Alias “ShellExecuteW” (hwnd As Integer, lpOperation As WString, lpFile As WString, lpParameters As WString, lpDirectory As WString, nShowCmd As Int32) As Integer
ok = ShellExecute(0, “RunAS”, filename, params, “”, SW_HIDE)

'We could do something fancy here
If ok > 32 Then
'everything worked
system.DebugLog(“Elevation worked!”)
Else
Select Case ok
Case SE_ERR_ACCESSDENIED
'User declined elevation
system.DebugLog(“User declined elevation”)
Else
'Something else went wrong
system.DebugLog(“Uh oh!”)
End Select
End If

'Or we just could just return the result so the caller can handle the error
Return ok
End Function
[/code]

[quote=422045:@]Take care of it all during install when the installer does the elevation
Elevate the app so the UAC pops up. This can be done a few ways:
[/quote]

I’m currently using a helper app and elevating it, but your code looks more robust than what I’ve been using, I’ll check it out, thank you!

Ah cool, no problem. Failing all that just store it in AppData\Local and don’t go near the registry :slight_smile: