C ++如何检测Windows 10

时间:2015-08-20 10:02:37

标签: c++ windows windows-10

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

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

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

欢迎任何其他建议/想法!

6 个答案:

答案 0 :(得分:14)

GetVersion和GetVersionEx被various version helper functions取代。你想要的是IsWindows10OrGreater。它们可以在 VersionHelpers.h 中找到。

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

请记住,此功能所涉及的参数与Windows内部版本号和非市场营销名称相关。所以Windows 8是构建6.2。 Windows 7是6.0等。

答案 1 :(得分:12)

从Windows 8.1开始,GetVersion()GetVersionEx()受申请表现限制:

  

随着Windows 8.1的发布,GetVersionEx API的行为已更改为操作系统版本返回的值。 GetVersionEx函数返回的值现在取决于应用程序的显示方式。

     

未在Windows 8.1或Windows 10中显示的应用程序将返回Windows 8操作系统版本值(6.2)。一旦应用程序显示给定的操作系统版本,GetVersionEx将始终返回应用程序在将来的版本中显示的版本。要显示Windows 8.1或Windows 10的应用程序,请参阅Targeting your application for Windows

较新的Version Helper functions只是VerifyVersionInfo()的包装器。从Windows 10开始,它现在也会受到表现:

  

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

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

Version Helper functions使用VerifyVersionInfo函数,因此行为IsWindows8Point1OrGreaterIsWindows10OrGreater同样会受到清单的存在和内容的影响。

     

要显示Windows 8.1或Windows 10的应用程序,请参阅Targeting your application for Windows

要获得 true 操作系统版本而不管显示,Microsoft建议查询系统DLL的文件版本:

Getting the System Version

  

要获取操作系统的完整版本号,请调用其中一个系统DLL上的GetFileVersionInfo函数,例如Kernel32.dll,然后调用VerQueryValue以获取{{1}文件版本信息的子块。

另一种方法是使用RtlGetVersion()NetServerGetInfo()NetWkstaGetInfo()代替。他们都报告了一个准确的操作系统版本,并且不受表现(但是?)。

答案 2 :(得分:1)

我需要这个来处理旧版本的VS编译器,而且更需要在Qt框架内工作。以下是我如何实现这一目标。

将此文件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

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

msvc: LIBS += -lKernel32

实现类似的辅助函数(注意这里使用的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
...

现在,这是真正的关键。您需要将一个清单文件附加到您的exe文件中,该文件将“#34; target&#34;最新的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>

这里有一些批量附加清单:

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%"

理论上,您可以使用qmake运行附加清单的最后一位。我找到的例子并没有运气,只是被骗了#34;现在这个批次......

答案 3 :(得分:1)

使用以下功能:

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

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

答案 4 :(得分:1)

#include <iostream>
#include <windows.h>
#pragma comment(lib, "Version.lib" )

BOOL GetOsVersion()
{
    wchar_t path[200] = L"C:\\Windows\\System32\\kernel32.dll";
    DWORD dwDummy;
    DWORD dwFVISize = GetFileVersionInfoSize(path, &dwDummy);
    LPBYTE lpVersionInfo = new BYTE[dwFVISize];
    if (GetFileVersionInfo(path, 0, dwFVISize, lpVersionInfo) == 0)
    {
        return FALSE;
    }

    UINT uLen;
    VS_FIXEDFILEINFO* lpFfi;
    BOOL bVer = VerQueryValue(lpVersionInfo, L"\\", (LPVOID*)&lpFfi, &uLen);

    if (!bVer || uLen == 0)
    {
        return FALSE;
    }
    DWORD dwProductVersionMS = lpFfi->dwProductVersionMS;
    if (HIWORD(dwProductVersionMS) == 10 && LOWORD(dwProductVersionMS) == 0)
    {
        cout << "this is windows 10\n";
    }
    else if (HIWORD(dwProductVersionMS) == 6 && LOWORD(dwProductVersionMS) == 3)
    {
        cout << "this is windows 8.1\n";
    }
    else if (HIWORD(dwProductVersionMS) == 6 && LOWORD(dwProductVersionMS) == 2)
    {
        cout << "this is windows 8\n";
    }
    else if (HIWORD(dwProductVersionMS) == 6 && LOWORD(dwProductVersionMS) == 1)
    {
        cout << "this is windows 7 or Windows Server 2008 R2\n";
    }
    else if (HIWORD(dwProductVersionMS) == 6 && LOWORD(dwProductVersionMS) == 0)
    {
        cout << "this is windows Vista or Windows Server 2008\n";
    }
    else if (HIWORD(dwProductVersionMS) == 5 && LOWORD(dwProductVersionMS) == 2)
    {
        cout << "this is windows Server 2003\n";
    }
    else if (HIWORD(dwProductVersionMS) == 5 && LOWORD(dwProductVersionMS) == 1)
    {
        cout << "this is windows Server XP\n";
    }
    else if (HIWORD(dwProductVersionMS) == 5 && LOWORD(dwProductVersionMS) == 0)
    {
        cout << "this is windows 2000\n";
    }
    //else if (lpFfi->dwFileVersionMS == 4 && lpFfi->dwFileVersionLS == 90)
    //{
    //    cout << "this is windows  Me\n";
    //}
    //else if (lpFfi->dwFileVersionMS == 4 && lpFfi->dwFileVersionLS == 10)
    //{
    //    cout << "this is windows  98\n";
    //}
    //else if (lpFfi->dwFileVersionMS == 4 && lpFfi->dwFileVersionLS == 0)
    //{
    //    cout << "this is windows  95\n";
    //}
    return TRUE;
}

测试用于检测win10的代码后。

我推测此api错误IsWindows10OrGreater是因为为kernel32.dll设置了错误的FileVersionMS版本。使用ProductVersionMS版本查询可以正常获取它。

https://docs.microsoft.com/en-us/windows/win32/api/versionhelpers/nf-versionhelpers-iswindows10orgreater

希望它可以帮助所有人!

答案 5 :(得分:0)

不要使用VersionHelpers.h!有问题!

它会忽略用户的应用程序兼容性设置。

相反,使用旧的 Kernel32.dll 函数,如 GetVersion,例如:

bool IsWindowsVersionOrGreater(unsigned short version)
{
    return _byteswap_ushort((unsigned short)GetVersion()) >= version;
}

// Usage: IsWindowsVersionOrGreater(_WIN32_WINNT_WINTHRESHOLD)