在W10上检查Windows版本

ADe*_*v75 10 delphi operating-system windows-10 delphi-xe8

有谁知道TOSVersion.Name是否仍适用于Windows 10?

我有一个vcl应用程序,它有一个表单show事件,它获取操作系统的详细信息,并使用SysUtils的TOSVersion记录在TMemo框中显示它们.

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;
Run Code Online (Sandbox Code Playgroud)

代码在XP上没有任何问题执行(是的我们仍在使用它(羞愧地停下来)),Vista,Windows 7,Windows 8.1,台式电脑,笔记本电脑和Surface Pro,但在Windows 10上安装时却没有.

当我使用paserver调试时,TOSVersion.Name返回为:='Windows 8'.我做错了什么,或者我期望TOSVersion能够检测到Windows 10?没有例外被触发.在我可以访问的2台Windows 10机器中,一条迁移路径来自Windows 8.1,另一条迁移路径来自Windows 7.

非常感谢

Dav*_*nan 11

有两件事会阻止您的代码返回正确的版本:

  1. 您使用的XE8 RTL早于Windows 10,因此不了解Windows 10.
  2. 您的可执行文件本身并不表现为支持Windows 10,等等GetVersionEx,这TOSVersion依赖,会撒谎的版本.

事实上,XE8更新1,我认为,更改版本检测使用NetWkstaGetInfo不受此版本谎言.虽然调用NetWkstaGetInfo确实泄漏了内存,但这可能并不重要,因为它只被调用一次.

与此主题相关的一些链接:

如果您绝对必须向用户报告版本,那么您有多种选择:

  • 将该supportedOS选项添加到清单中并包含Windows 10的GUID GetVersionEx.然后使用修改版本TOSVersion或其他方法获取版本.
  • 使用WMI查询.
  • 打电话NetServerGetInfo.
  • 打电话NetWkstaGetInfo.
  • 打电话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;
Run Code Online (Sandbox Code Playgroud)