简体   繁体   English

检测 Windows 10 版本

[英]Detecting Windows 10 version

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 10,它必须跨平台以及跨不同版本的 Windows(至少 7 及更高版本)工作。 Windows provides IsWindows10OrGreater() to tackle this problem, but there's another issue with it, this function isn't present in previous windows versions. Windows 提供了IsWindows10OrGreater()来解决这个问题,但它还有另一个问题,这个函数在以前的 Windows 版本中不存在。

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.你会发现无数关于这个的博客和 SO 问题,以及像 this 和 getversion 等函数返回一些不同版本而不是正确版本的明显疯狂。

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

So is there a sane multi-version way I could solve this problem?那么有没有一种理智的多版本方法可以解决这个问题?

The most straight-forward way to retrieve the true OS version is to call RtlGetVersion .检索真实操作系统版本的最直接方法是调用RtlGetVersion It is what GetVersionEx and VerifyVersionInfo call, but doesn't employ the compatibility shims.这是GetVersionExVerifyVersionInfo调用的,但不使用兼容性垫片。

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

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

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).如果您需要其他信息,您可以传递RTL_OSVERSIONINFOEXW结构代替RTL_OSVERSIONINFOW结构(正确分配dwOSVersionInfoSize成员)。

This returns the expected result on Windows 10, even when there is no manifest attached.即使没有附加清单,这也会在 Windows 10 上返回预期结果。


As an aside, it is commonly accepted as a better solution to provide different implementations based on available features rather than OS versions. 顺便说一句,根据可用功能而不是操作系统版本提供不同的实现,这被普遍认为是更好的解决方案。

IsWindows10OrGreater() from VersionHelpers.h来自VersionHelpers.h IsWindows10OrGreater()

Check the notes at Version Helper functions on MSDN查看MSDN版本助手功能的注释

File VersionHelpers.h is shipped with Windows 10 SDK, but it will work in previous versions, too.文件VersionHelpers.h随 Windows 10 SDK 一起提供,但它也适用于以前的版本。 Just copy it to your development environment.只需将其复制到您的开发环境即可。

It's just a header-only defined small lib, which uses VerSetConditionMask and VerifyVersionInfoW functions, both available in WinAPI since Windows 2000.它只是一个仅标头定义的小库,它使用VerSetConditionMaskVerifyVersionInfoW函数,这两个函数自 Windows 2000 起在 WinAPI 中可用。

Upd If you can not include manifest file with your source code, you can use simple hack: just get a version of any system dll, for example, kernel32.dll using GetFileVersionInfo function. Upd如果您的源代码不能包含清单文件,您可以使用简单的技巧:只需使用GetFileVersionInfo函数获取任何系统 dll 的版本,例如kernel32.dll

You can read real build number from the registry, and then infer Windows version from it.您可以从注册表中读取真实的内部版本号,然后从中推断出 Windows 版本。 Your application does not need to have a manifest for this work: on my machine, it correctly detects OS build number as 10586. For example:您的应用程序不需要为此工作提供清单:在我的机器上,它正确地检测到操作系统内部版本号为 10586。例如:

#include <Windows.h>
#include <sstream>

struct HKeyHolder
{
private:
    HKEY m_Key;

public:
    HKeyHolder() :
        m_Key(nullptr)
    {
    }

    HKeyHolder(const HKeyHolder&) = delete;
    HKeyHolder& operator=(const HKeyHolder&) = delete;

    ~HKeyHolder()
    {
        if (m_Key != nullptr)
            RegCloseKey(m_Key);
    }

    operator HKEY() const
    {
        return m_Key;
    }

    HKEY* operator&()
    {
        return &m_Key;
    }
};

bool IsRunningOnWindows10()
{
    HKeyHolder currentVersion;
    if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, LR"(SOFTWARE\Microsoft\Windows NT\CurrentVersion)", 0, KEY_QUERY_VALUE, &currentVersion) != ERROR_SUCCESS)
        return false;

    DWORD valueType;
    BYTE buffer[256];
    DWORD bufferSize = 256;

    if (RegQueryValueExW(currentVersion, L"CurrentBuild", nullptr, &valueType, buffer, &bufferSize) != ERROR_SUCCESS)
        return false;

    if (valueType != REG_SZ)
        return false;

    int version;
    std::wistringstream versionStream(reinterpret_cast<wchar_t*>(buffer));
    versionStream >> version;

    return version > 9800;
}
// should work on all platforms from Windows XP to Windows 10

NTSTATUS(WINAPI * RtlGetVersion)(LPOSVERSIONINFOEXW);
OSVERSIONINFOEXW osInfo;

*(FARPROC*)&RtlGetVersion = GetProcAddress(GetModuleHandleA("ntdll"), "RtlGetVersion");

if ( NULL != RtlGetVersion )
{
    osInfo.dwOSVersionInfoSize = sizeof(osInfo);
    RtlGetVersion(&osInfo);

    osInfo.dwMajorVersion;osInfo.dwMinorVersion; osInfo.dwBuildNumber;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM