In my last blog post Getting the Windows version, I claimed that there is no way to get the actual version number of Windows 10 without reading the version information of the Kernel32.dll and interpreting it 1.
Since then I have been told that there is actually a Registry key that contains the Windows version:
It has several entries that can be used to get the same version info that the Winver tool displays to the user. On Windows 10 that’s:
On my test installation they get me
“Windows 10 Pro” Version “1809” (OS Build “17762”.”437″)
(The quotes denote values read from the registry.)
By changing the ReleaseId value I verified that Winver (at least the on my Windows 10 installation) also reads these entries.
Some of these entries are available for older versions of Windows too, while some other entries apparently are only available in older versions. On the installations I have available for tests, it looks like this:
|Entry||Windows 10||Windows 8.1||Windows 7|
There are some other interesting entries there, but I won’t go into that any further.
So I wrote another function that reads these entries and creates a version string from it. It returns the following results:
|7||Windows 7 Professional (OS Build 7601.24411) Service Pack 1|
|8.1||Windows 8.1 Pro (OS Build 9600.19327)|
|10||Windows 10 Pro Version 1809 (OS Build 17763.437)|
There is one catch though: Windows 64 bit versions by default return different view of the registry to 32 bit programs than they do to 64 bit programs. In order for a 32 bit program to read the “real” registry, it must open the registry specifying the KEY_WOW64_64KEY flag in addition to the desired access.
So here is the code:
function TryGetWindowsVersionFromRegistry(out _Values: TWinCurrentRec): Boolean; var Reg: TRegistry; begin // We need to read the real registry, not the 32 bit view, because some of the entries // don't exist there. Reg := TRegistry.Create(KEY_READ or KEY_WOW64_64KEY); try Reg.RootKey := HKEY_LOCAL_MACHINE; Result := Reg.OpenKeyReadOnly('SOFTWARE\Microsoft\Windows NT\CurrentVersion'); if not Result then Exit; //==> _Values.BuildLab := TRegistry_ReadString(Reg, 'BuildLab'); _Values.BuildLabEx := TRegistry_ReadString(Reg, 'BuildLabEx'); _Values.CSDBuildNumber := TRegistry_ReadString(Reg, 'CSDBuildNumber'); _Values.CSDVersion := TRegistry_ReadString(Reg, 'CSDVersion'); _Values.CurrentBuildNumber := TRegistry_ReadString(Reg, 'CurrentBuildNumber'); _Values.CurrentVersion := TRegistry_ReadString(Reg, 'CurrentVersion'); _Values.EditionId := TRegistry_ReadString(Reg, 'EditionId'); _Values.ProductName := TRegistry_ReadString(Reg, 'ProductName'); _Values.ReleaseId := TRegistry_ReadString(Reg, 'ReleaseId'); _Values.UBR := TRegistry_ReadInteger(Reg, 'UBR'); finally FreeAndNil(Reg); end; end; function GetWindowsVersionStringFromRegistry: string; var Values: TWinCurrentRec; begin if not TryGetWindowsVersionFromRegistry(Values) then begin Result := _('Unknown Windows 10 version (registry key does not exist)'); Exit; //==> end; if Values.ProductName = '' then begin Result := _('Unknown Windows version (ProductName entry cannot be read)'); Exit; //==> end; Result := Values.ProductName; if Values.ReleaseId <> '' then Result := Result + ' Version ' + Values.ReleaseId; if Values.CurrentBuildNumber <> '' then begin Result := Result + ' (OS Build ' + Values.CurrentBuildNumber; if Values.UBR <> 0 then Result := Result + '.' + IntToStr(Values.UBR); Result := Result + ')'; end; if Values.CSDVersion <> '' then Result := Result + ' ' + Values.CSDVersion; end;
That code works even with Delphi 6, but you will have to declare the constant
KEY_WOW64_64KEY = $0100;
there since it did not exist when Delphi 6 was released. It does exist in Delphi 2007. I haven’t tried other versions.
These functions are again also available in the unit u_dzOsUtils of my dzlib library.
If you would like to comment on this, go to this post in the international Delphi Praxis forum.
1 Actually I did not want to claim that there is no way but that I could not find one. ↩