我已经写了很多年前的PC审计工具,并且一直保持最新状态。 其中一个基本function是报告正在审计的PC上运行的Windows版本,我一直使用GetVersionEx调用。
这可以运行在Windows 8之上,但在Windows 10下不受支持,Windows 8的确如Windows 8一样返回8.2。 微软似乎没有引入任何东西作为直接替代,而是build议您检查所需的特定function,而不是查看操作系统,但为了审计的目的,我确实需要操作系统名称。
“扫描仪”是一个C ++程序,必须在非特权帐户下运行,所以我不认为我已经读过的另一个build议 – 拿起系统DLL的版本,如kernel32.dll将工作,因为这些文件夹通常是不可访问的给用户。
任何其他的build议/想法是最受欢迎的!
GetVersion和GetVersionEx被各种版本的helper函数取代。 你想要的是IsWindows10OrGreater 。 它们可以在VersionHelpers.h中找到。
IsWindows10OrGreater仅在最新的SDK / Visual Studio 2015中可用。但是,您可以在一般情况下使用IsWindowsVersionOrGreater 。 例如,在我的7盒子上,我得到了IsWindowsVersionOrGreater(6,0,0)的 TRUE。
记住这个函数的参数与Windows内部版本号相关,而不是市场名称。 所以Windows 8是建立6.2。 Windows 7是6.0等
从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显示您的应用程序,请参阅针对您的Windows应用程序 。
较新的版本帮助器函数只是VerifyVersionInfo()
包装器。 从Windows 10开始,它现在也受到显示的影响:
如果设置了
lpVersionInfo
参数,即使当前操作系统版本为Windows 8.1或Windows 8.1时,Windows 10:VerifyVersionInfo
在由没有Windows 8.1或Windows 10兼容性清单的应用程序调用时VerifyVersionInfo
返回false,或者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函数使用
VerifyVersionInfo
函数,因此行为IsWindows8Point1OrGreater
和IsWindows10OrGreater
同样受清单的存在和内容的影响。要为Windows 8.1或Windows 10显示您的应用程序,请参阅针对您的Windows应用程序 。
为了获得真正的操作系统版本而不管表现形式如何,Microsoft建议查询系统DLL的文件版本:
获取系统版本
若要获取操作系统的完整版本号,请在其中一个系统DLL(如
coreel32.dll
上调用GetFileVersionInfo
函数,然后调用VerQueryValue
以获取\\StringFileInfo\\<lang><codepage>\\ProductVersion
子块文件版本信息。
另一种方法是使用RtlGetVersion()
, NetserverGetInfo()
或NetWkstaGetInfo()
来代替。 他们都报告一个准确的操作系统版本,并不会显示(还?)。
我需要这个在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 += -lcoreel32
像这样实现帮助函数(注意这里使用的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文件,它将“定位”最近的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来运行附加清单的最后一位。 我没有运气,我发现的例子,只是“欺骗”与这批现在…