问题描述
有谁知道 TOSVersion.Name 是否仍然适用于 Windows 10?
Does anyone know if TOSVersion.Name still works on Windows 10?
我有一个 vcl 应用程序,它有一个表单显示事件,该事件获取操作系统详细信息并使用来自 SysUtils 的 TOSVersion 记录将它们显示在 TMemo 框中.
I have a vcl application that has a form show event that gets the operating system details and displays them in a TMemo box using TOSVersion record from SysUtils.
with mmoOSInfo.Lines do
begin
Clear;
Add(TOSVersion.ToString);
Add('');
Add('Architecture: ' + OSArchitectureToStr(TOSVersion.Architecture));
Add('Platform: ' + OSPlatformToStr(TOSVersion.Platform) +
IntToStr(PlatformFromPointer));
Add('Build: ' + IntToStr(TOSVersion.Build));
Add('Major: ' + IntToStr(TOSVersion.Major));
Add('Minor: ' + IntToStr(TOSVersion.Minor));
Add('Name: ' + TOSVersion.Name);
Add('Service Pack - Major: ' + IntToStr(TOSVersion.ServicePackMajor));
Add('Service Pack - Minor: ' + IntToStr(TOSVersion.ServicePackMinor));
end;
代码在 XP(是的,我们仍在使用它(羞愧地垂头丧气))、Vista、Windows 7、Windows 8.1、台式电脑、笔记本电脑和 Surface Pro 上没有任何问题,但在 Windows 10 上安装时没有任何问题.
The code executes without any issues on XP (Yes we're still using it (hangs head in shame)), Vista, Windows 7, Windows 8.1, Desktop PC's, laptops and Surface Pro's but not when installed on Windows 10.
当我使用 paserver 进行调试时,TOSVersion.Name 返回为 := 'Windows 8'.我做错了什么还是我对 TOSVersion 检测 Windows 10 的期望过高?没有异常被触发.在我可以访问的 2 台 Windows 10 计算机中,一个迁移路径是从 Windows 8.1 迁移,而另一个迁移路径是从 Windows 7 迁移.
When I debug using paserver, TOSVersion.Name comes back as := 'Windows 8'.Am I doing something wrong or am I expecting too much for TOSVersion to detect Windows 10? No exception is being triggered. Of the 2 x Windows 10 machines I have access to, one migration path was from Windows 8.1, the other one however was from Windows 7.
非常感谢
推荐答案
有两件事会阻止您的代码返回正确的版本:
Two things stop your code from returning the correct version:
- 您使用的 XE8 RTL 早于 Windows 10,因此不了解 Windows 10.
- 您的可执行文件本身并不支持 Windows 10,因此 TOSVersion 依赖的 ">
GetVersionEx
会对版本撒谎.
我相信 XE8 更新 1 碰巧将版本检测更改为使用不受此版本谎言约束的 NetWkstaGetInfo
.虽然对 NetWkstaGetInfo
的调用确实会泄漏内存,但这可能并不重要,因为它只被调用一次.
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:
- Windows 8.1 和 Windows Server 2012 中的操作系统版本变化R2
- 为什么 Windows 8.1 有时会告诉您它是 Windows 8.0
GetVersionEx
- 针对 Windows 应用程序立>
- 还有更多....
如果您绝对必须向用户报告版本,那么您有多种选择:
If you absolutely must report the version to the user, then you have a variety of options:
- 将
supportedOS
选项添加到您的清单,并包含适用于 Windows 10 的 GUID.这可以防止GetVersionEx
撒谎.然后使用TOSVersion
的修改版本或其他方式来获取版本. - 使用 WMI 查询.
- 调用
NetServerGetInfo
. - 调用
NetWkstaGetInfo
. - 调用
RtlGetVersion
.
- Add the
supportedOS
option to your manifest and include the GUID for Windows 10. That stopsGetVersionEx
from lying. Then use a modified version ofTOSVersion
, or some other means, to obtain the version. - Use a WMI query.
- Call
NetServerGetInfo
. - Call
NetWkstaGetInfo
. - Call
RtlGetVersion
.
这个问题的更多细节:如何检测真正的 Windows 版本?尽管请注意,那里接受的答案已过时.
More details in this question: How to detect true Windows version? Although note that the accepted answer there is out-of-date.
作为 WMI 方法的示例,您可以使用以下代码:
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;
这篇关于在 W10 上检查 Windows 版本的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!