I have seen in a few questions/answers on how to detect the OS version of Win 8.1 and 10.0 using VerifyVersionInfo (since GetVersionEx no longer works without manifesting), but this only allows me to check if the OS is a version you pass to the function. It does not return this info to me. For example, with GetVersionEx it would tell me the major, minor, and build versions, but with VerifyVersionInfo I have to essentially ask "Is the OS version 6.3 or greater?" or "Is the OS version 10.0 or greater?" since GetVersionEx now returns 6.2 for the OS version even if it is actually 6.3 or 10.0.
This is fine in that I can easily add this check to my code, but I now have no way of getting the build version since VerifyVersionInfo does not tell me this. Is it possible to still get the build version by some other means?
Here is what I am doing now to determine if the OS is 8.1 or 10.0:
function IsWindowsVersionOrGreater(wMajorVersion, wMinorVersion, wServicePackMajor: Word): Boolean;
var
osvi: OSVersionInfoEX;
dwlConditionMask: Int64;
begin
FillChar(osvi, sizeof(osvi), 0);
osvi.dwOSVersionInfoSize := SizeOf(osvi);
osvi.dwMajorVersion := wMajorVersion;
osvi.dwMinorVersion := wMinorVersion;
osvi.wServicePackMajor := wServicePackMajor;
dwlConditionMask := VerSetConditionMask(0, VER_MAJORVERSION, VER_GREATER_EQUAL);
dwlConditionMask := VerSetConditionMask(dwlConditionMask, VER_MINORVERSION, VER_GREATER_EQUAL);
dwlConditionMask := VerSetConditionMask(dwlConditionMask, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL);
Result := VerifyVersionInfo(osvi, VER_MAJORVERSION or VER_MINORVERSION or VER_SERVICEPACKMAJOR, dwlConditionMask);
end;
function IsWindows8Point1OrGreater: Boolean;
begin
Result := IsWindowsVersionOrGreater(HIBYTE(WIN32_WINNT_WINBLUE), LOBYTE(WIN32_WINNT_WINBLUE), 0);
end;
function IsWindows10OrGreater: Boolean;
begin
Result := IsWindowsVersionOrGreater(HIBYTE(WIN32_WINNT_WIN10), LOBYTE(WIN32_WINNT_WIN10), 0);
end;
function GetWinVersion: string;
var
osVerInfo: TOSVersionInfo;
majorVersion, minorVersion: Integer;
begin
Result := '?.?';
osVerInfo.dwOSVersionInfoSize := SizeOf(TOSVersionInfo) ;
if GetVersionEx(osVerInfo) then
begin
minorVersion := osVerInfo.dwMinorVersion;
majorVersion := osVerInfo.dwMajorVersion;
if (majorVersion = 6) and (minorVersion = 2) then
begin
if IsWindows10OrGreater() then // 8.1+ does not report correct version.
Result := '10.0' // NOTE: NO BUILD NUMBER
else if IsWindows8Point1OrGreater() then
Result := '6.3'
else // This 6.2 is actually Win 8
result:=inttostr(majorVersion)+'.'+inttostr(minorVersion)+'.'+inttostr(osVerInfo.dwBuildNumber);
end
else
result:=inttostr(majorVersion)+'.'+inttostr(minorVersion)+'.'+inttostr(osVerInfo.dwBuildNumber);
end;
end;
EDIT: As suggested by David, the solution was to use WMI. This works with Win 8.1 and Win 10 and does not need you to keep an updated manifest with each new version of Windows.
function GetWinVersion8AndUp(): String;
const
WbemUser ='';
WbemPassword ='';
WbemComputer ='localhost';
wbemFlagForwardOnly = $00000020;
var
FSWbemLocator : OLEVariant;
FWMIService : OLEVariant;
FWbemObjectSet: OLEVariant;
FWbemObject : OLEVariant;
oEnum : IEnumvariant;
iValue : LongWord;
begin;
Result := '';
try
try
FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
FWMIService := FSWbemLocator.ConnectServer(WbemComputer, 'root\CIMV2', WbemUser, WbemPassword);
FWbemObjectSet:= FWMIService.ExecQuery('SELECT * FROM Win32_OperatingSystem','WQL',wbemFlagForwardOnly);
oEnum := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
while oEnum.Next(1, FWbemObject, iValue) = 0 do
begin
Result := Format('%s',[String(FWbemObject.Version)]);
FWbemObject:=Unassigned;
end;
except
end;
finally
end;
end;