检测 Windows 10 版本

2021-12-17 00:00:00 windows winapi c++

我的目标是在我的代码中检测 Windows 10,它必须跨平台以及跨不同版本的 Windows(至少 7 和更高版本)工作.Windows 提供了 IsWindows10OrGreater() 来解决这个问题,但它还有另一个问题,这个函数在以前的 Windows 版本中不存在.

My objective is to detect Windows 10 in my code which has to work cross-platform as well as across different versions of Windows (atleast 7 & up). Windows provides IsWindows10OrGreater() to tackle this problem, but there's another issue with it, this function isn't present in previous windows versions.

您会发现无数关于此的博客和 SO 问题,以及像 this 和 getversion 等函数返回一些不同版本而不是正确版本的明显疯狂.

You'll find countless blogs and SO questions regarding this as well as the manifest madness where functions like this and getversion and others return some different version rather than the correct one.

例如在我的机器上 - 方法 IsWindows10OrGreater() 无法编译(我必须安装 Win10 SDK),并且 IsWindowsVersionOrGreater() 报告 6 作为主要版本.

For example on my machine - the method IsWindows10OrGreater() doesn't compile(I would've to install Win10 SDK), and IsWindowsVersionOrGreater() reports 6 as major version.

那么有没有一种理智的多版本方法可以解决这个问题?

So is there a sane multi-version way I could solve this problem?

推荐答案

检索真实操作系统版本的最直接方法是调用 RtlGetVersion.这是 GetVersionExVerifyVersionInfo 调用的,但不使用兼容性垫片.

The most straight-forward way to retrieve the true OS version is to call RtlGetVersion. It is what GetVersionEx and VerifyVersionInfo call, but doesn't employ the compatibility shims.

您可以使用 DDK(通过 #include <ntddk.h> 并从内核模式链接 NtosKrnl.lib,或从用户模式链接 ntdll.lib),或者使用运行时动态链接,如下面的代码片段所示:

You can either use the DDK (by #including <ntddk.h> and linking against NtosKrnl.lib from kernel mode, or ntdll.lib from user mode), or use runtime dynamic linking as in the following snippet:

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;
}

如果您需要其他信息,您可以传递 RTL_OSVERSIONINFOEXW 结构代替 RTL_OSVERSIONINFOW 结构(正确分配 dwOSVersionInfoSize 成员).

In case you need additional information you can pass an RTL_OSVERSIONINFOEXW structure in place of the RTL_OSVERSIONINFOW structure (properly assigning the dwOSVersionInfoSize member).

这会在 Windows 10 上返回预期结果,即使没有附加清单也是如此.

This returns the expected result on Windows 10, even when there is no manifest attached.


顺便说一句,根据可用的功能而不是操作系统版本提供不同的实现被普遍认为是更好的解决方案.


As an aside, it is commonly accepted as a better solution to provide different implementations based on available features rather than OS versions.

相关文章