获得Windows系统版本信息的正确姿势On Windows10

文章目录

参考资料:
Targeting your application for Windows.aspx)

这两天想对一个程序进行升级,原始程序只支持win7。要对系统版本进行确定,正确显示出系统版本信息,本来应该是一个非常简单的事情但是但是为什么在win10上系统版本还是6.2呢buildnumber为什么还是9200呢。奇怪。。。。。
既然有问题咱们就来想想有哪些可能性吧:

  • 1.Win10系统是测试版,系统内核版本信息等都还是win8的
  • 2.由于使用的是vs2008编译的,可能是程序默认使用兼容性方式运行所以获得的是win8系统信息
  • 3.打开程序姿势不对,哈哈
    先试试win10系统吧,由于不记得win10是什么时候装的只有systeminfo看看系统信息。嗯,系统版本buildnumber是10240对的是win10正式版,排除1。
    再看哈2,程序信息没有选择以兼容性模式运行啊。对了,突然想到好像某些时候只要程序不显式声明支持新系统默认直接兼容运行,那怎么显式声明呢?这里就需要我们前面一篇Visual Studio使用备注中提到过的manifest文件,vc6中添加看那篇文章第8点。vs2008附加添加直接vs工程属性里找到“清单工具->输入和输出->附加清单文件”里填入manifest文件的相对路径,然后重新链接。
    针对win10的manifest文件如下:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    <exe>.manifest
    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
    <assemblyIdentity
    type="win32"
    name=SXS_ASSEMBLY_NAME
    version=SXS_ASSEMBLY_VERSION
    processorArchitecture=SXS_PROCESSOR_ARCHITECTURE
    />
    <description> my foo exe </description>
    <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
    <security>
    <requestedPrivileges>
    <requestedExecutionLevel
    level="asInvoker"
    uiAccess="false"
    />
    </requestedPrivileges>
    </security>
    </trustInfo>
    <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 Vista -->
    <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
    <!-- Windows 7 -->
    <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
    <!-- Windows 8 -->
    <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
    </application>
    </compatibility>
    </assembly>

加上后重新编译果然正确获得信息,试试我新装的vs2015 “error C4996: ‘GetVersionExW’: 被声明为已否决”才发现原来是GetVersionEx这个api已经不提供支持了。赶紧查查msdn,发现说得很清楚“[GetVersionEx may be altered or unavailable for releases after Windows 8.1. Instead, use the Version Helper APIs]With the release of Windows 8.1, the behavior of the GetVersionEx API has changed in the value it will return for the operating system version. The value returned by the GetVersionEx function now depends on how the application is manifested”。

msdn上说由于GetVersionEx获得的信息有可能会改变在win8.1以后,这些api将由Version Helper functions.aspx)代替,继续往下翻 发现有很多人抱怨由于这个api不能用,嗯 然后还有人给出解决方案,这个才是我想要的
so 根据这些线索我这里总结出在win10上正确获得系统版本信息的方式:
1.在程序中嵌入正确的manifest文件,就是上面说的。显式声明我支持win10
2.通过更换api,使用Version Helper APIs
3.通过NtQueryInformationProcess获得进程环境块peb地址然后偏移0xa4开始就是关于系统版本信息,在Peb(Process Environment Block)简单学习及分析有简单介绍
4.通过使用native api解决RtlGetVersion

这几种方法推荐使用第4种,基本和原始GetVersionEx相同,不用改动太多。

附上代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
//通过peb方式获得系统版本信息
#include <Windows.h>
#include <winternl.h>
#include <stdio.h>

DWORD Major;
DWORD Minor;
DWORD Build;

typedef NTSTATUS (WINAPI* _NtQueryInformationProcess)
(_In_ HANDLE ProcessHandle, _In_ PROCESSINFOCLASS ProcessInformationClass,
_Out_ PVOID ProcessInformation, _In_ ULONG ProcessInformationLength, _Out_opt_ PULONG ReturnLength)
;

_NtQueryInformationProcess NtQueryInformationProcess_;

DWORD GetProcessPEBAddress(HANDLE hProc)
{

PROCESS_BASIC_INFORMATION peb;
DWORD tmp;
NtQueryInformationProcess_ = (_NtQueryInformationProcess)GetProcAddress(GetModuleHandle("ntdll.dll"), "NtQueryInformationProcess");
NtQueryInformationProcess_(hProc, ProcessBasicInformation, &peb, sizeof(PROCESS_BASIC_INFORMATION), &tmp);
return (DWORD)peb.PebBaseAddress;
}

void OSVersion(HANDLE handle)
{

DWORD pebAddress = GetProcessPEBAddress(handle);
DWORD OSMajorVersionAddress = pebAddress + 0x0a4;
DWORD OSMinorVersionAddress = pebAddress + 0x0a8;
DWORD OSBuildNumberAddress = pebAddress + 0x0ac;
ReadProcessMemory(handle, (void*)OSMajorVersionAddress, &Major, sizeof(Major), 0);
ReadProcessMemory(handle, (void*)OSMinorVersionAddress, &Minor, sizeof(Minor), 0);
ReadProcessMemory(handle, (void*)OSBuildNumberAddress, &Build, sizeof(Build), 0);
}

int main()
{

HANDLE handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId());
OSVersion(handle);

printf("OS version - %d.%d.%d", Major, Minor, Build);

getchar();
return 0;
}

//通过RtlGetVersion api获得系统信息

LONG (WINAPI *pfnRtlGetVersion)(RTL_OSVERSIONINFOEXW*);
(FARPROC&)pfnRtlGetVersion = GetProcAddress(GetModuleHandle(_T("ntdll.dll")), "RtlGetVersion");
if(pfnRtlGetVersion)
{
RTL_OSVERSIONINFOEXW ver = {0};
ver.dwOSVersionInfoSize = sizeof(ver);

if(pfnRtlGetVersion(&ver) == 0)
{
//Success, read results in `ver`
}
else
{
//RtlGetVersion failed
}
}
else
{
//RtlGetVersion was not found...
}

最后总结哈,msdn很重要,出现问题应该第一时间查询msdn。经常更新IDE版本很重要,使用新的IDE可以帮助我们检查代码中可能的问题

##后记补充参考
——20151220——–这篇文章写得很好很详细
Windows系统版本判定那些事儿