有两件事会阻止您的代码返回正确的版本:
- 您使用的 XE8 RTL 早于 Windows 10,因此不了解 Windows 10。
- 您的可执行文件本身并不支持 Windows 10,因此GetVersionEx, which
TOSVersion
依赖,会谎报版本。
碰巧的是,我相信 XE8 update 1 更改了版本检测以使用NetWkstaGetInfo
这不受此版本谎言的约束。尽管致电NetWkstaGetInfo
确实泄漏内存,但这可能并不重要,因为它只被调用一次。
与此主题相关的一些链接:
- Windows 8.1 和 Windows Server 2012 R2 中的操作系统版本更改
- 为什么 Windows 8.1 有时会告诉您它是 Windows 8.0
- GetVersionEx
- 将您的应用程序定位为 Windows
- 还有很多很多......
如果您绝对必须向用户报告版本,那么您有多种选择:
- Add the
supportedOS
选项到您的清单并包含 Windows 10 的 GUID。这将停止GetVersionEx
来自说谎。然后使用修改后的版本TOSVersion
或其他方式来获取版本。
- 使用 WMI 查询。
- Call
NetServerGetInfo
.
- Call
NetWkstaGetInfo
.
- Call
RtlGetVersion
.
这个问题的更多细节:如何检测真实的Windows版本?尽管请注意,接受的答案已经过时了。
作为 WMI 方法的示例,您可以使用以下代码:
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;