C++ 如何检测 Windows 10

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/32115255/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 14:05:28  来源:igfitidea点击:

C++ How to detect Windows 10

c++windowswindows-10

提问by user1169502

I have written a PC auditing tool many years ago and have been keeping it up to date. One of basic functions is reporting the version of Windows running on the PC being audited for which I have always used the GetVersionEx call.

多年前我编写了一个 PC 审计工具,并且一直在更新它。其中一项基本功能是报告正在审核的 PC 上运行的 Windows 版本,我一直使用 GetVersionEx 调用来获取这些版本。

This works up to and including Windows 8 but is not supported under Windows 10 and indeed Windows 10 returns 8.2 just as windows 8 does. Microsoft do not seem to have introduced anything as a direct replacement suggesting instead that you check for specific features required rather than looking at the OS but for the purpose of the audit I actually want the OS name.

这适用于并包括 Windows 8,但在 Windows 10 下不受支持,实际上 Windows 10 返回 8.2,就像 Windows 8 一样。微软似乎没有引入任何直接替代的东西,而是建议您检查所需的特定功能而不是查看操作系统,但出于审计的目的,我实际上想要操作系统名称。

The 'scanner' is a C++ program which must run under non-privileged accounts so I don't think another suggestion I have read - picking up the version of a system DLL such as kernel32.dll will work as these folders are typically not accessible to users.

“扫描仪”是一个 C++ 程序,它必须在非特权帐户下运行,所以我认为我读过的另一个建议不是 - 选择系统 DLL 的版本(例如 kernel32.dll)将起作用,因为这些文件夹通常无法访问给用户。

Any other suggestions/thoughts are most welcome!

任何其他建议/想法是最受欢迎的!

回答by Robinson

GetVersion and GetVersionEx were superseded by various version helper functions. The one you want is IsWindows10OrGreater. They can be found in VersionHelpers.h.

GetVersion 和 GetVersionEx 被各种版本辅助函数取代。您想要的是IsWindows10OrGreater。它们可以在VersionHelpers.h 中找到。

IsWindows10OrGreateris only available in the latest SDK/Visual Studio 2015. You can use IsWindowsVersionOrGreaterin the general case however. For example on my 7 box I get TRUE for IsWindowsVersionOrGreater(6, 0, 0).

IsWindows10OrGreater仅在最新的 SDK/Visual Studio 2015 中可用。但是,您可以在一般情况下使用IsWindowsVersionOrGreater。例如,在我的 7 盒子上,IsWindowsVersionOrGreater(6, 0, 0)为 TRUE 。

Remember that the parameters this function takes relate to Windows build number and NOT marketing name. So Windows 8 is build 6.2. Windows 7 is 6.0 etc.

请记住,此函数采用的参数与 Windows 内部版本号相关,而不是营销名称。所以 Windows 8 是 build 6.2。Windows 7 是 6.0 等。

回答by Remy Lebeau

Starting in Windows 8.1, GetVersion()and GetVersionEx()are subject to application manifestation:

从 Windows 8.1 开始,GetVersion()GetVersionEx()受应用程序表现的约束:

With the release of Windows 8.1, the behavior of the GetVersionExAPI has changed in the value it will return for the operating system version. The value returned by the GetVersionExfunction now depends on how the application is manifested.

Applications not manifested for Windows 8.1 or Windows 10 will return the Windows 8 OS version value (6.2). Once an application is manifested for a given operating system version, GetVersionExwill always return the version that the application is manifested for in future releases. To manifest your applications for Windows 8.1 or Windows 10, refer to Targeting your application for Windows.

随着 Windows 8.1 的发布,GetVersionExAPI的行为在它为操作系统版本返回的值方面发生了变化。函数返回的值GetVersionEx现在取决于应用程序的显示方式。

未针对 Windows 8.1 或 Windows 10 显示的应用程序将返回 Windows 8 操作系统版本值 (6.2)。一旦为给定的操作系统GetVersionEx版本显示应用程序,将始终返回应用程序在未来版本中显示的版本。要显示适用于 Windows 8.1 或 Windows 10的应用程序,请参阅面向 Windows 的应用程序

The newer Version Helper functionsare simply wrappers for VerifyVersionInfo(). Starting in Windows 10, it is now subject to manifestation as well:

较新的版本助手函数只是VerifyVersionInfo(). 从 Windows 10 开始,它现在也有表现形式:

Windows 10: VerifyVersionInforeturns false when called by applications that do not have a compatibility manifest for Windows 8.1 or Windows 10 if the lpVersionInfoparameter is set so that it specifies Windows 8.1 or Windows 10, even when the current operating system version is Windows 8.1 or Windows 10. Specifically, VerifyVersionInfohas the following behavior:

  • If the application has no manifest, VerifyVersionInfobehaves as if the operation system version is Windows 8 (6.2).
  • If the application has a manifest that contains the GUID that corresponds to Windows 8.1, VerifyVersionInfobehaves as if the operation system version is Windows 8.1 (6.3).
  • If the application has a manifest that contains the GUID that corresponds to Windows 10, VerifyVersionInfobehaves as if the operation system version is Windows 10 (10.0).

The Version Helper functionsuse the VerifyVersionInfofunction, so the behavior IsWindows8Point1OrGreaterand IsWindows10OrGreaterare similarly affected by the presence and content of the manifest.

To manifest your applications for Windows 8.1 or Windows 10, see Targeting your application for Windows.

Windows 10:VerifyVersionInfo如果该lpVersionInfo参数设置为指定 Windows 8.1 或 Windows 10,即使当前操作系统版本是 Windows 8.1 或 Windows 10 ,当被没有 Windows 8.1 或 Windows 10 兼容性清单的应用程序调用时返回 false . 具体来说,VerifyVersionInfo有以下行为:

  • 如果应用程序没有清单,则VerifyVersionInfo表现为操作系统版本为 Windows 8 (6.2)。
  • 如果应用程序的清单包含对应于 Windows 8.1 的 GUID,VerifyVersionInfo则其行为就像操作系统版本是 Windows 8.1 (6.3)。
  • 如果应用程序的清单包含对应于 Windows 10 的 GUID,VerifyVersionInfo则其行为就像操作系统版本是 Windows 10 (10.0)。

版本助手功能使用VerifyVersionInfo功能,所以其行为IsWindows8Point1OrGreaterIsWindows10OrGreater同样受到清单的存在和内容。

若要显示适用于 Windows 8.1 或 Windows 10的应用程序,请参阅面向 Windows 的应用程序

To get the trueOS version regardless of manifestation, Microsoft suggests querying the file version of a system DLL:

为了获得真实的操作系统版本,无论表现如何,微软建议查询系统 DLL 的文件版本:

Getting the System Version

获取系统版本

To obtain the full version number for the operating system, call the GetFileVersionInfofunction on one of the system DLLs, such as Kernel32.dll, then call VerQueryValueto obtain the \\StringFileInfo\\<lang><codepage>\\ProductVersionsubblock of the file version information.

要获取操作系统的完整版本号,请在GetFileVersionInfo系统 DLL 之一上调用该函数,例如Kernel32.dll,然后调用VerQueryValue以获取\\StringFileInfo\\<lang><codepage>\\ProductVersion文件版本信息的子块。

Another way is to use RtlGetVersion(), NetServerGetInfo(), or NetWkstaGetInfo()instead. They all report an accurate OS version and are not subject to manifestation (yet?).

另一种方法是使用RtlGetVersion(), NetServerGetInfo(), 或NetWkstaGetInfo()代替。它们都报告了准确的操作系统版本,并且不受表现形式的影响(还没有?)。

回答by Michael Haephrati

Use the following function:

使用以下函数:

double getSysOpType()
{
    int ret = 0.0;
    NTSTATUS(WINAPI *RtlGetVersion)(LPOSVERSIONINFOEXW);
    OSVERSIONINFOEXW osInfo;

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

    if (NULL != RtlGetVersion)
    {
        osInfo.dwOSVersionInfoSize = sizeof(osInfo);
        RtlGetVersion(&osInfo);
        ret = osInfo.dwMajorVersion;
    }
    return ret;
}

It will return the Windows version as a double (7, 8, 8.1, 10).

它将以双精度形式返回 Windows 版本(7、8、8.1、10)。

回答by BuvinJ

I needed this to work on an older version of the VS compiler, and more over within a Qt framework. Here's how I accomplished that.

我需要它来处理旧版本的 VS 编译器,以及在 Qt 框架中的更多内容。这是我如何做到的。

Add this file GetWinVersion.hto your Qt project:

将此文件添加GetWinVersion.h到您的 Qt 项目中:

#ifndef GETWINVERSION
#define GETWINVERSION

#include <QtGlobal>

#ifdef Q_OS_WIN

#include <windows.h>
#include <stdio.h>

float GetWinVersion()
{
    OSVERSIONINFO osvi;
    ZeroMemory( &osvi, sizeof(OSVERSIONINFO) );
    osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
    return GetVersionEx( &osvi ) ?
           (float)osvi.dwMajorVersion +
           ((float)osvi.dwMinorVersion/10) :
           0.0 ;
}

#endif //Q_OS_WIN

#endif // GETWINVERSION

Add the required linkage in your pro or pri qmake file:

在您的 pro 或 pri qmake 文件中添加所需的链接:

msvc: LIBS += -lKernel32

Implement the helper function like so (note SystemInfo used here is a custom class of mine, but you get the idea...):

像这样实现辅助函数(注意这里使用的 SystemInfo 是我的自定义类,但你明白了......):

#include "GetWinVersion.h"

SystemInfo info;

#ifdef Q_OS_WIN
    info.setPlatform( SystemInfo::WINDOWS );
    switch(QSysInfo::windowsVersion())
    {
    case QSysInfo::WV_32s:        info.setOsName( L"3.1" );     info.setOsVersion( 3.1 ); break;
    case QSysInfo::WV_95:         info.setOsName( L"95" );      info.setOsVersion( 4.0 ); break;
    case QSysInfo::WV_98:         info.setOsName( L"98" );      info.setOsVersion( 4.1 ); break;
    case QSysInfo::WV_Me:         info.setOsName( L"Me" );      info.setOsVersion( 4.9 ); break;
    case QSysInfo::WV_NT:         info.setOsName( L"NT" );      info.setOsVersion( 4.0 ); break;
    case QSysInfo::WV_2000:       info.setOsName( L"2000" );    info.setOsVersion( 5.0 ); break;
    case QSysInfo::WV_XP:         info.setOsName( L"XP" );      info.setOsVersion( 5.1 ); break;
    case QSysInfo::WV_2003:       info.setOsName( L"2003" );    info.setOsVersion( 5.2 ); break;  // Windows Server 2003, Windows Server 2003 R2, Windows Home Server, Windows XP Professional x64 Edition
    case QSysInfo::WV_VISTA:      info.setOsName( L"Vista" );   info.setOsVersion( 6.0 ); break;  // Windows Vista, Windows Server 2008
    case QSysInfo::WV_WINDOWS7:   info.setOsName( L"7" );       info.setOsVersion( 6.1 ); break;  // Windows 7, Windows Server 2008 R2
    case QSysInfo::WV_WINDOWS8:   info.setOsName( L"8" );       info.setOsVersion( 6.2 ); break;  // Windows 8, Windows Server 2012
  // These cases are never reached due to Windows api changes
  // As of Qt 5.5, this not accounted for by QSysInfo::windowsVersion()
  //case QSysInfo::WV_WINDOWS8_1: info.setOsName( L"8.1" );     info.setOsVersion( 6.3 ); break;  // Windows 8.1, Windows Server 2012 R2
  //case QSysInfo::WV_WINDOWS10:  info.setOsName( L"10" );      info.setOsVersion( 10.0 ); break; // Windows 10, Windows Server 2016
    default:
        // On Windows 8.1 & 10, this will only work when the exe
        // contains a manifest which targets the specific OS's
        // you wish to detect.  Else 6.2 (ie. Win 8.0 is returned)
        info.setOsVersion( GetWinVersion() );
        if(      info.osVersion() == 6.3f )  // Windows 8.1, Windows Server 2012 R2
            info.setOsName( L"8.1" );
        else if( info.osVersion() == 10.0f ) // Windows 10, Windows Server 2016
            info.setOsName( L"10" );
        else
            info.setOsName( L"UNKNOWN" );
    }
    info.setOsBits( IsWow64() ? 64 : 32 );
#else
...

Now here's the real key. You need to attach a manifest file to your exe which will "target" the recent Windows versions, else you can't detect them (see the MS docs: https://msdn.microsoft.com/en-us/library/windows/desktop/ms724451%28v=vs.85%29.aspx). Here's an example manifest to do this:

现在这是真正的关键。您需要将清单文件附加到您的 exe 文件,该文件将“针对”最近的 Windows 版本,否则您无法检测到它们(请参阅 MS 文档:https: //msdn.microsoft.com/en-us/library/windows /desktop/ms724451%28v=vs.85%29.aspx)。这是执行此操作的示例清单:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
    <assemblyIdentity 
        name="MyOrg.MyDept.MyAppName" 
        version="1.0.0.0" 
        processorArchitecture="x86" 
        type="win32" />
    <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 8 -->
            <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
            <!-- Windows 7 -->
            <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>      
            <!-- Windows Vista -->
            <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>          
        </application> 
    </compatibility>
</assembly>

And here's some batch to attach the manifest:

这是一些附加清单的批处理:

set exeFile=MyApp.exe
set manifestFile=MyApp.manifest
set manifestExe=C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\bin\x64\mt.exe

"%manifestExe%" -manifest "%manifestFile%" -outputresource:"%exeFile%"

In theory, you can use qmake to run that last bit attaching the manifest. I didn't have luck with the examples I found, and just "cheated" with this batch for now...

理论上,您可以使用 qmake 来运行附加清单的最后一点。我发现的例子并不走运,现在只是“欺骗”了这批……