Two things stop your code from returning the correct version:
- The XE8 RTL that you use predates Windows 10 and so has no knowledge of Windows 10.
- Your executable does not manifest itself as supporting Windows 10, and so
GetVersionEx
, which TOSVersion
relies upon, will lie about the version.
It so happens that XE8 update 1, I believe, changes the version detection to use NetWkstaGetInfo
which is not subject to this version lie. Although the call to NetWkstaGetInfo
does leak memory, but that's probably not important since it is only called once.
Some links relating to this subject:
If you absolutely must report the version to the user, then you have a variety of options:
- Add the
supportedOS
option to your manifest and include the GUID for Windows 10. That stops GetVersionEx
from lying. Then use a modified version of TOSVersion
, or some other means, to obtain the version.
- Use a WMI query.
- Call
NetServerGetInfo
.
- Call
NetWkstaGetInfo
.
- Call
RtlGetVersion
.
More details in this question: How to detect true Windows version? Although note that the accepted answer there is out-of-date.
As an example of the WMI approach, you could use this code:
function OperatingSystemDisplayName: string;
function GetWMIObject(const objectName: string): IDispatch;
var
chEaten: Integer;
BindCtx: IBindCtx;
Moniker: IMoniker;
begin
OleCheck(CreateBindCtx(0, bindCtx));
OleCheck(MkParseDisplayName(BindCtx, PChar(objectName), chEaten, Moniker));
OleCheck(Moniker.BindToObject(BindCtx, nil, IDispatch, Result));
end;
function VarToString(const Value: OleVariant): string;
begin
if VarIsStr(Value) then begin
Result := Trim(Value);
end else begin
Result := '';
end;
end;
function FullVersionString(const Item: OleVariant): string;
var
Caption, ServicePack, Version, Architecture: string;
begin
Caption := VarToString(Item.Caption);
ServicePack := VarToString(Item.CSDVersion);
Version := VarToString(Item.Version);
Architecture := ArchitectureDisplayName(SystemArchitecture);
Result := Caption;
if ServicePack <> '' then begin
Result := Result + ' ' + ServicePack;
end;
Result := Result + ', version ' + Version + ', ' + Architecture;
end;
var
objWMIService: OleVariant;
colItems: OleVariant;
Item: OleVariant;
oEnum: IEnumvariant;
iValue: LongWord;
begin
Try
objWMIService := GetWMIObject('winmgmts:\\localhost\root\cimv2');
colItems := objWMIService.ExecQuery('SELECT Caption, CSDVersion, Version FROM Win32_OperatingSystem', 'WQL', 0);
oEnum := IUnknown(colItems._NewEnum) as IEnumVariant;
if oEnum.Next(1, Item, iValue)=0 then begin
Result := FullVersionString(Item);
exit;
end;
Except
// yes, I know this is nasty, but come what may I want to use the fallback code below should the WMI code fail
End;
(* Fallback, relies on the deprecated function GetVersionEx, reports erroneous values
when manifest does not contain supportedOS matching the executing system *)
Result := TOSVersion.ToString;
end;