首页 > 解决方案 > C++ 如何检测 Windows Server 2019?

问题描述

Microsoft 于 2018 年 10 月 2 日发布了 Windows Server 2019。从 Windows 2000 到此 Windows 版本,您可以使用 struct OSVERSIONINFOEX并根据 的变量调用 WinAPI 函数GetVersionEx,并确定 Windows 版本,例如 Windows 8.1, Windows 10、Windows Server 2012 R2。大家使用的代码是这样的:dwMajorVersiondwMinorVersionwProductType

OSVERSIONINFOEX osvi;
SecureZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
if (GetVersionEx(&osvi)) {
    if (osvi.dwMajorVersion == 10 &&
        osvi.dwMinorVersion == 0 &&
        osvi.wProductType != VER_NT_WORKSTATION) {
            Console->Log("We are running on Windows Server 2016");
        }
}

Wikipedia来看, Windows Server 2019 的 NT 10.0 版本号与 Server 2016 相同。所以上面的代码不再起作用。

此外,Microsoft Docs 包含以下注释:GetVersionEx 可能会更改或无法用于 Windows 8.1 之后的版本。相反,请使用 Version Helper 函数。

不幸的是,Version Helper 函数没有检测 Server 2019 的功能。另外,奇怪的是关于Targeting的 Docs 页面在 Windows 10 停止,并且没有谈论 Server 版本,而这些 Targeting manifests 是检测操作系统所必需的高于 Windows 8.1 或 Server 2012。

更新 1. 正如 @IInspectable 和 @RbMm 评论了RtlGetVersion函数的使用。所以我运行了以下代码(取自这个答案):

typedef LONG NTSTATUS, *PNTSTATUS;
#define STATUS_SUCCESS (0x00000000)

typedef NTSTATUS (WINAPI* RtlGetVersionPtr)(PRTL_OSVERSIONINFOW);

RTL_OSVERSIONINFOW GetRealOSVersion() {
    HMODULE hMod = ::GetModuleHandleW(L"ntdll.dll");
    if (hMod) {
        RtlGetVersionPtr fxPtr = (RtlGetVersionPtr)::GetProcAddress(hMod, "RtlGetVersion");
        if (fxPtr != nullptr) {
            RTL_OSVERSIONINFOW rovi = { 0 };
            rovi.dwOSVersionInfoSize = sizeof(rovi);
            if ( STATUS_SUCCESS == fxPtr(&rovi) ) {
                return rovi;
            }
        }
    }
    RTL_OSVERSIONINFOW rovi = { 0 };
    return rovi;
}

以下是Windows 10的结果:

视窗服务器 2019:

更新2。根据要求,发布从通过GetVersionEx调用获得的OSVERSIONINFOEX结构的完整信息,其中包含直到 Windows 10 的所有目标的清单文件(请参阅上面的目标链接):

// Windows 10
osvi.dwOSVersionInfoSize = 284
osvi.dwMajorVersion = 10
osvi.dwMinorVersion = 0
osvi.dwBuildNumber = 17134
osvi.dwPlatformId = 2
osvi.szCSDVersion =
osvi.wServicePackMinor = 0
osvi.wServicePackMinor = 0
osvi.wSuiteMask = 256  // 0x100
osvi.wProductType = 1
osvi.wReserved = 0

// Windows Server 2016
osvi.dwOSVersionInfoSize = 284
osvi.dwMajorVersion = 10
osvi.dwMinorVersion = 0
osvi.dwBuildNumber = 14393
osvi.dwPlatformId = 2
osvi.szCSDVersion =
osvi.wServicePackMinor = 0
osvi.wServicePackMinor = 0
osvi.wSuiteMask = 400
osvi.wProductType = 3
osvi.wReserved = 0

// Windows Server 2019
osvi.dwOSVersionInfoSize = 284
osvi.dwMajorVersion = 10
osvi.dwMinorVersion = 0
osvi.dwBuildNumber = 17763
osvi.dwPlatformId = 2
osvi.szCSDVersion =
osvi.wServicePackMinor = 0
osvi.wServicePackMinor = 0
osvi.wSuiteMask = 400  // 0x190
osvi.wProductType = 3
osvi.wReserved = 0

更新 3.RtlGetVersion使用结构调用RTL_OSVERSIONINFOEXW我们得到与更新 2 完全相同的结果。

标签: c++windowswinapi

解决方案


根据Windows Server 2019 版本信息中的讨论:

[Windows] Server 2019 Datacenter Edition build 17744,ReleaseId 字段显示 1809。

所以这样的事情应该可以解决问题:

const auto isWinServer2019Plus =
  IsWindowsServer() &&
  IsWindowsVersionOrGreater(10, 0, 1803);

推荐阅读