有人知道TOSVersion.Name是否仍可在Windows 10上运行吗?

我有一个vcl应用程序,它具有一个表单显示事件,该事件获取操作系统详细信息,并使用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;

该代码可以在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迁移的。

非常感谢

最佳答案

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

  • 您使用的XE8 RTL早于Windows 10,因此不了解Windows10。
  • 您的可执行文件并不表明自己支持Windows 10,因此GetVersionEx所依赖的 TOSVersion 将取决于版本。

  • 我相信XE8更新1确实将版本检测更改为使用不受此版本谎言约束的NetWkstaGetInfo。尽管对NetWkstaGetInfo的调用确实会泄漏内存,但这并不重要,因为它仅被调用了一次。

    一些与此主题有关的链接:
  • Operating system version changes in Windows 8.1 and Windows Server 2012 R2
  • Why Windows 8.1 Sometimes Tells You It Is Windows 8.0
  • GetVersionEx
  • Targeting your application for Windows
  • 还有更多....

  • 如果您绝对必须将版本报告给用户,那么您可以有多种选择:
  • supportedOS选项添加到 list 中,并包括Windows 10的GUID。这可以阻止GetVersionEx说谎。然后,使用TOSVersion的修改版本或其他某种方式来获取该版本。
  • 使用WMI查询。
  • 调用NetServerGetInfo
  • 调用NetWkstaGetInfo
  • 调用RtlGetVersion

  • 该问题的更多详细信息:How to detect true Windows version?尽管请注意,已接受的答案已过期。

    作为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;
    

    关于delphi - 在W10上检查Windows版本,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/32378851/

    10-17 02:44