Delphi 正在检查W10上的Windows版本

Delphi 正在检查W10上的Windows版本,delphi,operating-system,windows-10,delphi-xe8,Delphi,Operating System,Windows 10,Delphi Xe8,有人知道TOSVersion.Name是否仍能在Windows 10上运行吗 我有一个vcl应用程序,它有一个表单显示事件,该事件获取操作系统详细信息,并使用SysUtils中的TOSVersion记录将其显示在TMemo框中 with mmoOSInfo.Lines do begin Clear; Add(TOSVersion.ToString); Add(''); Add('Architecture: ' + OSArchitectureToStr(TOS

有人知道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、台式PC、笔记本电脑和Surface Pro上执行时没有任何问题,但在Windows 10上安装时则没有

当我使用PASServer进行调试时,TOSVersion.Name返回为:='Windows8'。 我是否做错了什么,或者我对TOSVersion检测Windows 10的期望过高?未触发任何异常。在我可以访问的2台Windows 10计算机中,一条迁移路径来自Windows 8.1,另一条则来自Windows 7


非常感谢

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

  • 您使用的XE8 RTL早于Windows 10,因此不了解Windows 10
  • 您的可执行文件不支持Windows 10,因此
    TOSVersion
    所依赖的版本将与该版本有关
  • 我认为,XE8 update 1将版本检测更改为使用
    NetWkstaGetInfo
    ,这不受此版本的限制。尽管对
    NetWkstaGetInfo
    的调用确实会泄漏内存,但这可能并不重要,因为它只被调用一次

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

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

    • supportedOS
      选项添加到清单中,并包括Windows 10的GUID。这可以阻止
      GetVersionEx
      撒谎。然后使用修改后的
      版本
      ,或其他方法获取版本
    • 使用WMI查询
    • 调用
      NetServerGetInfo
    • 调用
      NetWkstaGetInfo
    • 调用
      RtlGetVersion
    关于这个问题的更多细节:尽管请注意,公认的答案已经过时了

    作为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;
    
    函数操作系统显示名称:字符串;
    函数GetWMIObject(const objectName:string):IDispatch;
    变量
    chEaten:整数;
    BindCtx:IBindCtx;
    名字:伊莫尼克尔;
    开始
    olcheck(CreateBindCtx(0,bindCtx));
    olcheck(MkParseDisplayName(BindCtx、PChar(objectName)、chEaten、名字对象));
    OleCheck(名字对象BindToObject(BindCtx,nil,IDispatch,Result));
    结束;
    函数VarToString(const值:OleVariant):字符串;
    开始
    如果变量STR(值),则开始
    结果:=微调(值);
    结束,否则开始
    结果:='';
    结束;
    结束;
    函数FullVersionString(const项:OleVariant):字符串;
    变量
    标题、ServicePack、版本、体系结构:字符串;
    开始
    标题:=VarToString(Item.Caption);
    ServicePack:=VarToString(Item.csd版本);
    版本:=VarToString(Item.Version);
    架构:=架构显示名称(SystemArchitecture);
    结果:=标题;
    如果是ServicePack“”,则开始
    结果:=结果+“”+ServicePack;
    结束;
    结果:=结果+',版本'+版本+','+架构;
    结束;
    变量
    objWMIService:油变异体;
    大肠菌群:油变异体;
    项目:油变异体;
    oEnum:IEnumvariant;
    伊瓦鲁:长词;
    开始
    尝试
    objWMIService:=GetWMIObject('winmgmts:\\localhost\root\cimv2');
    colItems:=objWMIService.ExecQuery('SELECT Caption,CSDVersion,Version FROM Win32_OperatingSystem','WQL',0);
    oEnum:=IUnknown(colItems.\u NewEnum)作为IEnumVariant;
    如果oEnum.Next(1,项,值)=0,则开始
    结果:=完整版本字符串(项目);
    出口
    结束;
    除了
    //是的,我知道这很糟糕,但是如果WMI代码失败,我可能想使用下面的回退代码
    结束;
    (*回退,依赖于不推荐使用的函数GetVersionEx,报告错误的值
    清单不包含与执行系统*匹配的支持对象时*)
    结果:=TOSVersion.ToString;
    结束;
    
    您是否尝试过使用自定义清单

    我使用XE8,并且在使用针对Windows 8.1和Windows 10的清单文件时,识别Windows 10的版本没有问题

    我的自定义清单是为了让我的应用程序“Windows 10”知晓

    具体如下:

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
      <assemblyIdentity
        type="win32"
        name="MrTheV Dev"
        version="11.0.2804.9245"
        processorArchitecture="*"/>
      <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
        <security>
          <requestedPrivileges>
            <requestedExecutionLevel
              level="asInvoker"
              uiAccess="False"/>
            </requestedPrivileges>
        </security>
      </trustInfo>
      <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"> 
            <application> 
                <!-- Windows 10 --> 
                <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
                <!-- Windows 8.1 -->
                <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
                <!-- Windows Vista -->
                <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/> 
                <!-- Windows 7 -->
                <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
                <!-- Windows 8 -->
                <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
            </application> 
        </compatibility>
    </assembly>
    

    @杰瑞道奇,别再这样了。毫无疑问,根据营销类型,新版本正是您所需要的。您必须热爱营销:)-除此之外。如果我看一下这个链接(),将supportedOS条目添加到清单中还有其他含义。在答案中加入这一点也许是个好主意。非常感谢海夫曼先生。我非常感谢您对Delphi编程知识的深刻理解。另一个选择是从
    kernel32.dll
    中阅读版本,请参阅我尝试了您的代码,它除了编译
    体系结构DisplayName(SystemArchitecture)
    之外都可以编译。两个函数/变量/常量似乎都未知。我必须在
    uses
    子句中包含哪个文件来修复此问题?我已经包括了
    ActiveX
    。抱歉,上面的链接-我刚刚在Win 10上测试了该库,但它不起作用!
    Windows (Version 10.0, Build 14393, 64-bit Edition)