场景
- 开发
WTL/ATL/Win32
程序时, 有时候需要获取系统版本号,以便判断用户在使用软件时的系统。在某一天突然发现获取的系统版本号是错的, 一直是版本号6.2.x
,什么情况?
说明
- 如果软件没有针对
Win8.1
或Win10
以上的系统做兼容处理,返回的是Windows8
的OS
版本值6.2
。这就是为什么只调用Win32 API GetVersionEx
会一直返回6.2
的版本号原因[4]。要正确获取系统版本号,还要另外在程序清单文件里增加以下的配置,参考[1].
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- Windows 10 and Windows 11 -->
<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>
-
以
Visual Studio 2017
为例,在项目属性-》清单工具-》输入和输出-》附加清单文件 里增加文件gdi-aware.manifest
.- 注意以下部分时用于
DPI
处理的,可以去掉, 参考[5]:
<asmv3:application> <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings"> <dpiAware>true</dpiAware> </asmv3:windowsSettings> </asmv3:application>
- 注意以下部分是针对
32
位程序的兼容性问题的, 如果只支持64
位程序可以不用添加。
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3"> <security> <requestedPrivileges> <!-- UAC settings: - app should run at same integrity level as calling process - app does not need to manipulate windows belonging to higher-integrity-level processes --> <requestedExecutionLevel level="asInvoker" uiAccess="false" /> </requestedPrivileges> </security> </trustInfo>
- 注意以下部分时用于
例子
-
注意,这个文件一般用于嵌入清单,这样
EXE
程序不会因为没有清单文件而导致获取错误。 -
在没嵌入清单文件
gdi-aware.manifest
前,在Win11
上获取系统版本号是6.2.9200 Service Pack 0.0
, 嵌入之后的到正确的版本号10.0.22631 Service Pack 0.0
。
test.cpp
void TestGetOSVersion()
{
OSVERSIONINFOEX osver = { 0 };
osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
// 6.2.9200 Service Pack 0.0
// gdi-aware.manifest
// 10.0.22631 Service Pack 0.0
if (GetVersionEx((LPOSVERSIONINFO)&osver)){
cout << osver.dwMajorVersion << "." << osver.dwMinorVersion << "." << osver.dwBuildNumber
<< " Service Pack " << osver.wServicePackMajor << "."
<< osver.wServicePackMinor << endl;
}
else {
cout << "Error" << endl;
}
}
gdi-aware.manifest
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
<asmv3:application>
<asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
<dpiAware>true</dpiAware>
</asmv3:windowsSettings>
</asmv3:application>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- Windows 10 and Windows 11 -->
<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>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<!--
UAC settings:
- app should run at same integrity level as calling process
- app does not need to manipulate windows belonging to
higher-integrity-level processes
-->
<requestedExecutionLevel
level="asInvoker"
uiAccess="false"
/>
</requestedPrivileges>
</security>
</trustInfo>
</assembly>