【问题标题】:How to detect true Windows version?如何检测真正的 Windows 版本?
【发布时间】:2010-09-08 14:22:20
【问题描述】:

我知道我可以调用 GetVersionEx Win32 API 函数来检索 Windows 版本。在大多数情况下,返回值反映了我的 Windows 版本,但有时并非如此。

如果用户在兼容层下运行我的应用程序,则 GetVersionEx 不会报告真实版本,而是兼容层强制执行的版本。例如,如果我运行 Vista 并在“Windows NT 4”兼容模式下执行我的程序,GetVersionEx 不会返回 6.0 版本而是 4.0。

有没有办法绕过这种行为并获得真正的 Windows 版本?

【问题讨论】:

  • 遇到这个问题的人也应该看看这篇文章。 Version Checking (Just Don’t Do It) 版本检查很难正确。在从这个 SO 问题的答案中复制粘贴代码之前,请确保您绝对需要首先执行此操作。
  • 好问题,我也想知道这一点,并返回其他信息,例如 Service Pack、Home/Professional/Ultimate 版等。
  • 克雷格;检查我的 JCL 答案。它不会绕过兼容层,但它会告诉你是否 Windows 没有被配置为对你撒谎,它可以告诉你有关版本和所有内容的信息。
  • scobi 提供的链接的archive.org 链接:web.archive.org/web/20121013161123/http://windowsteamblog.com/…

标签: windows delphi winapi version


【解决方案1】:

WMI 查询:

"Select * from Win32_OperatingSystem"

编辑:实际上更好的是:

"Select Version from Win32_OperatingSystem"

你可以像这样在 Delphi 中实现它:

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;

【讨论】:

  • WMI 的一个问题 - 它仅在 Windows 2000 中引入。如果您知道您的代码不会在 9x 或 NT 3/4 上运行,那么 WMI 方法就可以了。
  • 还有人运行 9x 或 NT 吗?
  • WMI 是不是很奇怪? “选择”在我的 WMI 上不起作用,但 "path Win32_OperatingSystem" 确实有效。 WMI 是一种没有充分记录的疯狂,还是什么?
  • 所以您正在通过 wmic 控制台应用程序访问 wmi,这听起来像是。当我说 WMI 查询时,我指的是通过支持 WQL 查询语言(我意识到这是多余的)的方法访问它,而 WMIC 不支持。因此,要回答您的问题,WMI 的某些部分并没有特别完善的文档,因为任何软件供应商都可以像注册表一样随意在 WMI 中创建类,但是由 MS 创建的部分,尤其是处理操作系统的部分是实际上记录得很好。
【解决方案2】:

我知道的最佳方法是检查是否从某个 DLL 导出了特定的 API。每个新的 Windows 版本都添加了新功能,通过检查这些功能的存在,我们可以知道应用程序在哪个操作系统上运行。例如,Vista 从 kernel32.dll 导出 GetLocaleInfoEx,而以前的 Windows 没有。

长话短说,这里有一个这样的列表,其中仅包含 kernel32.dll 的导出。

> *功能:实现于* > GetLocaleInfoEx:Vista > GetLargePageMinimum:Vista,Server 2003 获取DLL目录:Vista、Server 2003、XP SP1 GetNativeSystemInfo:Vista、Server 2003、XP SP1、XP 替换文件:Vista、Server 2003、XP SP1、XP、2000 OpenThread:Vista、Server 2003、XP SP1、XP、2000、ME GetThreadPriorityBoost:Vista、Server 2003、XP SP1、XP、2000、NT 4 IsDebuggerPresent:Vista、Server 2003、XP SP1、XP、2000、ME、NT 4、98 GetDiskFreeSpaceEx:Vista、Server 2003、XP SP1、XP、2000、ME、NT 4、98、95 OSR2 ConnectNamedPipe:Vista、Server 2003、XP SP1、XP、2000、NT 4、NT 3 哔声:Vista、Server 2003、XP SP1、XP、2000、ME、98、95 OSR2、95

编写确定真实操作系统版本的函数很简单;只需从最新的操作系统到最旧的操作系统,并使用GetProcAddress 检查导出的 API。用任何语言实现它应该是微不足道的。

Delphi 中的以下代码是从免费的DSiWin32 库中提取的):

TDSiWindowsVersion = (wvUnknown, wvWin31, wvWin95, wvWin95OSR2, wvWin98,
  wvWin98SE, wvWinME, wvWin9x, wvWinNT3, wvWinNT4, wvWin2000, wvWinXP,
  wvWinNT, wvWinServer2003, wvWinVista);

function DSiGetWindowsVersion: TDSiWindowsVersion;
var
  versionInfo: TOSVersionInfo;
begin
  versionInfo.dwOSVersionInfoSize := SizeOf(versionInfo);
  GetVersionEx(versionInfo);
  Result := wvUnknown;
  case versionInfo.dwPlatformID of
    VER_PLATFORM_WIN32s: Result := wvWin31;
    VER_PLATFORM_WIN32_WINDOWS:
      case versionInfo.dwMinorVersion of
        0:
          if Trim(versionInfo.szCSDVersion[1]) = 'B' then
            Result := wvWin95OSR2
          else
            Result := wvWin95;
        10:
          if Trim(versionInfo.szCSDVersion[1]) = 'A' then
            Result := wvWin98SE
          else
            Result := wvWin98;
        90:
          if (versionInfo.dwBuildNumber = 73010104) then
             Result := wvWinME;
           else
             Result := wvWin9x;
      end; //case versionInfo.dwMinorVersion
    VER_PLATFORM_WIN32_NT:
      case versionInfo.dwMajorVersion of
        3: Result := wvWinNT3;
        4: Result := wvWinNT4;
        5:
          case versionInfo.dwMinorVersion of
            0: Result := wvWin2000;
            1: Result := wvWinXP;
            2: Result := wvWinServer2003;
            else Result := wvWinNT
          end; //case versionInfo.dwMinorVersion
        6: Result := wvWinVista;
      end; //case versionInfo.dwMajorVersion
    end; //versionInfo.dwPlatformID
end; { DSiGetWindowsVersion }

function DSiGetTrueWindowsVersion: TDSiWindowsVersion;

  function ExportsAPI(module: HMODULE; const apiName: string): boolean;
  begin
    Result := GetProcAddress(module, PChar(apiName)) <> nil;
  end; { ExportsAPI }

var
  hKernel32: HMODULE;

begin { DSiGetTrueWindowsVersion }
  hKernel32 := GetModuleHandle('kernel32');
  Win32Check(hKernel32 <> 0);
  if ExportsAPI(hKernel32, 'GetLocaleInfoEx') then
    Result := wvWinVista
  else if ExportsAPI(hKernel32, 'GetLargePageMinimum') then
    Result := wvWinServer2003
  else if ExportsAPI(hKernel32, 'GetNativeSystemInfo') then
    Result := wvWinXP
  else if ExportsAPI(hKernel32, 'ReplaceFile') then
    Result := wvWin2000
  else if ExportsAPI(hKernel32, 'OpenThread') then
    Result := wvWinME
  else if ExportsAPI(hKernel32, 'GetThreadPriorityBoost') then
    Result := wvWinNT4
  else if ExportsAPI(hKernel32, 'IsDebuggerPresent') then  //is also in NT4!
    Result := wvWin98
  else if ExportsAPI(hKernel32, 'GetDiskFreeSpaceEx') then  //is also in NT4!
    Result := wvWin95OSR2
  else if ExportsAPI(hKernel32, 'ConnectNamedPipe') then
    Result := wvWinNT3
  else if ExportsAPI(hKernel32, 'Beep') then
    Result := wvWin95
  else // we have no idea
    Result := DSiGetWindowsVersion;
end; { DSiGetTrueWindowsVersion }

--- 2009-10-09 更新

事实证明,在 Vista SP1 及更高版本上进行“未记录的”操作系统检测变得非常困难。查看API changes 显示所有Windows 2008 功能也在Vista SP1 中实现,所有Windows 7 功能也在Windows 2008 R2 中实现。太糟糕了:(

---更新结束

FWIW,这是我在实践中遇到的一个问题。我们(我工作的公司)有一个程序,当 Vista 发布时(以及在那之后的几个星期......),它并没有真正为 Vista 做好准备。它也不能在兼容层下工作。 (一些 DirectX 问题。不要问。)

我们根本不希望太聪明的用户在 Vista 上运行这个应用程序 - 是否兼容模式 - 所以我必须找到一个解决方案(一个比我聪明的人向我指出正确的方向;上面的东西不是我的创意)。现在我发布它是为了您的快乐,并帮助所有将来必须解决这个问题的可怜的灵魂。谷歌,请索引这篇文章!

如果您有更好的解决方案(或我的升级和/或修复),请在此处发布答案...

【讨论】:

  • 我很想编辑这篇文章以对齐第一部分中的版本,但我没有足够的声誉。
  • 这应该很容易翻译成 C#。
  • 不确定该表是否可信,AFAIK Beep 存在于 NT4 上,ConnectNamedPipe 存在于 9x
  • JEDI JCL 也可以确定服务器版本。
  • @WarrenP,那会是哪个 JCL 函数?
【解决方案3】:

获取系统文件的版本怎么样?

最好的文件是 kernel32.dll,位于 %WINDIR%\System32\kernel32.dll。

有获取文件版本的API。例如:我使用的是 Windows XP ->“5.1.2600.5512 (xpsp.080413-2111)”

【讨论】:

  • 这是 MSDN 推荐的方法。
【解决方案4】:

另一种解决方案:

读取以下注册表项:

HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProductName

或来自

的其他键
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion

【讨论】:

  • 现在,这很优雅。我很高兴我继续阅读而不是开始使用 GetVersionEx 选项。保持简单和美观。
  • 从注册表中读取字符串并解析它们不是一个好主意,除非 Microsoft 专门记录了它。您确定 ProductName 没有本地化为不同的语言吗?你确定你得到了产品名称的每一个变体吗?上述建议正是让 Microsoft 的 App Compat 团队大发雷霆的原因。 -1
  • 好吧,那么他们应该提供 API/官方解决方案来获取此信息。隐藏信息很少是好事。如您所见,每个解决方案都只是一种变通方法。
  • 当我在我的 Windows 8.1 笔记本电脑上阅读 CurrentVersion 时,令人惊讶的是它返回了“5.1”(Windows XP 的版本号)!这是使用较旧的 Delphi 7 应用程序,没有专门针对 Windows 8.1 的清单。使用regedit,该值肯定是“6.3”。这表明 Windows 必须故意拦截读取并应用某种兼容性填充程序。我发现唯一可靠的方法是根据 botismarius 的其他建议读取核心系统 dll 的版本号(我选择了kernel32.dll)。看起来有点“hacky”,但它确实有效。
  • 从上面继续,ProductName 在实际输入为“Windows 8.1”时返回“Microsoft Windows XP”!
【解决方案5】:

注意: Gabr 询问的是一种可以绕过GetVersionEx 限制的方法。 JCL 代码使用 GetVersionEx,因此受兼容层的约束。此信息仅适用于不需要绕过兼容层的人。

使用Jedi JCL,可以添加单元JclSysInfo,调用函数GetWindowsVersion。它返回一个枚举类型 TWindowsVersion。

目前,JCL 包含所有已发布的 Windows 版本,并且每次 Microsoft 在一个盒子中发布新版本的 Windows 时都会更改:

  TWindowsVersion =
   (wvUnknown, wvWin95, wvWin95OSR2, wvWin98, wvWin98SE, wvWinME,
    wvWinNT31, wvWinNT35, wvWinNT351, wvWinNT4, wvWin2000, wvWinXP,
    wvWin2003, wvWinXP64, wvWin2003R2, wvWinVista, wvWinServer2008,
    wvWin7, wvWinServer2008R2);

如果您想知道您运行的是 64 位 Windows 7 而不是 32 位,请致电 JclSysInfo.IsWindows64

请注意,JCL 也处理版本,如 Pro、Ultimate 等。对于该调用 GetWindowsEdition,它会返回以下之一:

TWindowsEdition =
   (weUnknown, weWinXPHome, weWinXPPro, weWinXPHomeN, weWinXPProN, weWinXPHomeK,
    weWinXPProK, weWinXPHomeKN, weWinXPProKN, weWinXPStarter, weWinXPMediaCenter,
    weWinXPTablet, weWinVistaStarter, weWinVistaHomeBasic, weWinVistaHomeBasicN,
    weWinVistaHomePremium, weWinVistaBusiness, weWinVistaBusinessN,
    weWinVistaEnterprise, weWinVistaUltimate, weWin7Starter, weWin7HomeBasic,
    weWin7HomePremium, weWin7Professional, weWin7Enterprise, weWin7Ultimate);

为了历史兴趣,你也可以用 NtProductType 函数查看 NT 级别的版本,它返回:

 TNtProductType =       (ptUnknown, ptWorkStation, ptServer, ptAdvancedServer,        
        ptPersonal, ptProfessional, ptDatacenterServer, 
        ptEnterprise, ptWebEdition);

请注意,上面检测到“N 个版本”。那是根据欧盟反垄断法规创建的欧盟(欧洲)版本的 Windows。这是 JCL 内部的一个非常好的检测等级。

这是一个示例函数,可帮助您检测 Vista,并在 Vista 上执行一些特殊操作。

function IsSupported:Boolean;
begin
  case GetWindowsVersion of
     wvVista:  result := false; 
    else
      result := true;
  end;
end;

请注意,如果您想进行“大于”检查,那么您应该使用其他技术。另请注意,版本检查通常会成为未来破坏的根源。我通常选择警告用户并继续,这样我的二进制代码就不会成为未来的实际破坏源。

最近我尝试安装一个应用程序,安装程序检查了我的驱动器可用空间,但没有安装,因为我有超过 2 GB 的可用空间。安装程序中的 32 位整数有符号值变为负数,从而破坏了安装程序。我必须将它安装到虚拟机中才能使其工作。添加“智能代码”通常会使您的应用程序“愚蠢”。小心点。

顺便说一句,我发现可以从命令行运行 WMIC.exe,然后键入 path Win32_OperatingSystem(“从 Win32_OperatingSystem 中选择 *”对我不起作用)。将来也许可以扩展 JCL 以使用 WMI 信息。

【讨论】:

    【解决方案6】:

    真实版本存储在进程信息的 PEB 块上。

    Win32 应用程序示例(Delphi 代码)

    unit RealWindowsVerUnit;
    
    interface
    
    uses
      Windows;
    
    var
      //Real version Windows
      Win32MajorVersionReal: Integer;
      Win32MinorVersionReal: Integer;
    
    implementation
    
    type
      PPEB=^PEB;
      PEB = record
        InheritedAddressSpace: Boolean;
        ReadImageFileExecOptions: Boolean;
        BeingDebugged: Boolean;
        Spare: Boolean;
        Mutant: Cardinal;
        ImageBaseAddress: Pointer;
        LoaderData: Pointer;
        ProcessParameters: Pointer; //PRTL_USER_PROCESS_PARAMETERS;
        SubSystemData: Pointer;
        ProcessHeap: Pointer;
        FastPebLock: Pointer;
        FastPebLockRoutine: Pointer;
        FastPebUnlockRoutine: Pointer;
        EnvironmentUpdateCount: Cardinal;
        KernelCallbackTable: PPointer;
        EventLogSection: Pointer;
        EventLog: Pointer;
        FreeList: Pointer; //PPEB_FREE_BLOCK;
        TlsExpansionCounter: Cardinal;
        TlsBitmap: Pointer;
        TlsBitmapBits: array[0..1] of Cardinal;
        ReadOnlySharedMemoryBase: Pointer;
        ReadOnlySharedMemoryHeap: Pointer;
        ReadOnlyStaticServerData: PPointer;
        AnsiCodePageData: Pointer;
        OemCodePageData: Pointer;
        UnicodeCaseTableData: Pointer;
        NumberOfProcessors: Cardinal;
        NtGlobalFlag: Cardinal;
        Spare2: array[0..3] of Byte;
        CriticalSectionTimeout: LARGE_INTEGER;
        HeapSegmentReserve: Cardinal;
        HeapSegmentCommit: Cardinal;
        HeapDeCommitTotalFreeThreshold: Cardinal;
        HeapDeCommitFreeBlockThreshold: Cardinal;
        NumberOfHeaps: Cardinal;
        MaximumNumberOfHeaps: Cardinal;
        ProcessHeaps: Pointer;
        GdiSharedHandleTable: Pointer;
        ProcessStarterHelper: Pointer;
        GdiDCAttributeList: Pointer;
        LoaderLock: Pointer;
        OSMajorVersion: Cardinal;
        OSMinorVersion: Cardinal;
        OSBuildNumber: Cardinal;
        OSPlatformId: Cardinal;
        ImageSubSystem: Cardinal;
        ImageSubSystemMajorVersion: Cardinal;
        ImageSubSystemMinorVersion: Cardinal;
        GdiHandleBuffer: array [0..33] of Cardinal;
        PostProcessInitRoutine: Cardinal;
        TlsExpansionBitmap: Cardinal;
        TlsExpansionBitmapBits: array [0..127] of Byte;
        SessionId: Cardinal;
      end;
    
    //Get PEB block current win32 process
    function GetPDB: PPEB; stdcall;
    asm
      MOV EAX, DWORD PTR FS:[30h]
    end;
    
    initialization
      //Detect true windows wersion
      Win32MajorVersionReal := GetPDB^.OSMajorVersion;
      Win32MinorVersionReal := GetPDB^.OSMinorVersion;
    end.
    

    【讨论】:

    • 那个虚假的stdcall 让整个sn-p 高度怀疑。
    【解决方案7】:

    基本上回答重复的Q:Getting OS major, minor, and build versions for Windows 8.1 and up in Delphi 2007

    从 W2K 开始,您可以使用 NetServerGetInfo。 NetServerGetInfo 在 W7 和 W8.1 上返回正确信息,无法在 W10 上测试..

    function GetWinVersion: string;
    var
      Buffer: PServerInfo101;
    begin
      Buffer := nil;
      if NetServerGetInfo(nil, 101, Pointer(Buffer)) = NO_ERROR then
      try
         Result := <Build You Version String here>(
          Buffer.sv101_version_major,
          Buffer.sv101_version_minor,
          VER_PLATFORM_WIN32_NT // Save since minimum support begins in W2K
          );
      finally
        NetApiBufferFree(Buffer);
      end;
    end;
    

    【讨论】:

    • 等到您可以针对 Win10 进行测试可能会更有用,因为该主题已在最近的 q 中得到积极讨论:stackoverflow.com/questions/31753092
    • 我在 Windows 10 Preview 上测试了这段代码(我还没有发布版本)。如果清单中没有 Windows 10 GUID,NetServerGetInfo()(以及 ntdll.dll 中的 RtlGetVersion())将版本报告为 10.0,而GetVersionEx() 将版本报告为 6.2,如文档所述。
    • 很高兴知道,我需要等到“发生了什么”错误解决了 :)
    【解决方案8】:

    以下适用于我在 Windows 10 中没有在应用程序清单中列出的 Windows 10 GUID:

    uses
      System.SysUtils, Winapi.Windows;
    
    type
      NET_API_STATUS = DWORD;
    
      _SERVER_INFO_101 = record
        sv101_platform_id: DWORD;
        sv101_name: LPWSTR;
        sv101_version_major: DWORD;
        sv101_version_minor: DWORD;
        sv101_type: DWORD;
        sv101_comment: LPWSTR;
      end;
      SERVER_INFO_101 = _SERVER_INFO_101;
      PSERVER_INFO_101 = ^SERVER_INFO_101;
      LPSERVER_INFO_101 = PSERVER_INFO_101;
    
    const
      MAJOR_VERSION_MASK = $0F;
    
    function NetServerGetInfo(servername: LPWSTR; level: DWORD; var bufptr): NET_API_STATUS; stdcall; external 'Netapi32.dll';
    function NetApiBufferFree(Buffer: LPVOID): NET_API_STATUS; stdcall; external 'Netapi32.dll';
    
    type
      pfnRtlGetVersion = function(var RTL_OSVERSIONINFOEXW): LONG; stdcall;
    var
      Buffer: PSERVER_INFO_101;
      ver: RTL_OSVERSIONINFOEXW;
      RtlGetVersion: pfnRtlGetVersion;
    begin
      Buffer := nil;
    
      // Win32MajorVersion and Win32MinorVersion are populated from GetVersionEx()...
      ShowMessage(Format('GetVersionEx: %d.%d', [Win32MajorVersion, Win32MinorVersion])); // shows 6.2, as expected per GetVersionEx() documentation
    
      @RtlGetVersion := GetProcAddress(GetModuleHandle('ntdll.dll'), 'RtlGetVersion');
      if Assigned(RtlGetVersion) then
      begin
        ZeroMemory(@ver, SizeOf(ver));
        ver.dwOSVersionInfoSize := SizeOf(ver);
    
        if RtlGetVersion(ver) = 0 then
          ShowMessage(Format('RtlGetVersion: %d.%d', [ver.dwMajorVersion, ver.dwMinorVersion])); // shows 10.0
      end;
    
      if NetServerGetInfo(nil, 101, Buffer) = NO_ERROR then
      try
        ShowMessage(Format('NetServerGetInfo: %d.%d', [Buffer.sv101_version_major and MAJOR_VERSION_MASK, Buffer.sv101_version_minor])); // shows 10.0
      finally
        NetApiBufferFree(Buffer);
      end;
    end.
    

    更新NetWkstaGetInfo() 可能也可以工作,类似于 'NetServerGetInfo()`,但我还没有尝试过。

    【讨论】:

    • 我的 Delphi 7 应用程序在 Windows 8.1 上运行。从 ntdll.dll 调用 RtlGetVersion 会返回“5.1”(Windows XP 的版本号)。这与从GetVersionEx 返回的数字相同。还没试过Netapi32功能。
    • @remylebeau - 对于未来的兼容性(Windows 的未来版本),您认为这 3 种方法中哪一种更可靠? RtlGetVersion?
    • @AlainD 对我和其他所有使用它的人都很好(SO 上的许多帖子都表明了这一点)。您是否偶然让您的 EXE 在 XP 兼容模式下运行?如果没有兼容模式并且缺少合适的清单,GetVersionEx 将报告 Windows 8 的版本号,而不是 XP。
    • @RemyLebeau:是的,很好看!当我禁用 XP 兼容模式时,操作系统版本返回为 Major=6Minor=2(即 Windows 8)。此后在 Windows 10 上进行了尝试,结果相同。
    【解决方案9】:

    关于使用 NetServerGetInfo() 的注意事项,它在 Windows 10 (10240.th1_st1) 上仍然有效...

    https://msdn.microsoft.com/en-us/library/windows/desktop/aa370903%28v=vs.85%29.aspx

    sv101_version_major

    主要版本号和服务器类型。

    指定操作系统的主要发行版本号 在最低有效 4 位。服务器类型在 最高有效 4 位。中定义的 MAJOR_VERSION_MASK 位掩码 应用程序应使用 Lmserver.h 标头 {0x0F} 来获取 该成员的主要版本号。

    换句话说,(sv101_version_major & MAJOR_VERSION_MASK)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-23
      • 2011-02-18
      • 1970-01-01
      相关资源
      最近更新 更多