Windows 8 之前最常用获取操作系统版本的方法是调用 GetVersionEx 函数。而从 Windows8.1 之后,GetVersionEx 这个API被微软明文废弃了,Windows8.1开始之后(包括Windows10),这个API常规情况下返回值都是 6.2。微软MSDN官方给出的说法是 Windows 8 以后可以使用 VersionHelpers 中的 IsWindowsXPOrGreater、IsWindowsXPSP1OrGreater、IsWindowsVistaOrGreater、IsWindows7OrGreater、IsWindows8Point1OrGreater、IsWindows10OrGreater、IsWindowsServer等系列函数,但这些函数在 XP 和 Win7 中并不兼容。
下面给出一种方法获取 Windows XP ~ Windows 10 全系列版本方法:
原理:
- 用 GetFileVersionInfo 获取 kernel32.dll 文件的版本信息。
- 结合 GetVersionEx 得到全系系统版本。
Kernel32.dll 文件是微软系统下个版本都使用的公共库函数,每个系统版本下该文件的版本都对应系统版本,通过对此文件版本判断,即可断言该操作系统的版本。

#pragma comment(lib,"version.lib")
BOOL Z_GetSystemVersion(__out char* pszOSVersion, __in const int nOSSize, __out char* pszBuildVersion, __in const int nBuildSize)
{
OSVERSIONINFOEXA os;
SYSTEM_INFO si;
os.dwOSVersionInfoSize = sizeof(os);
GetNativeSystemInfo(&si);
#ifdef _WIN64
#pragma warning(disable: 4996)
#endif
if (GetVersionExA((OSVERSIONINFOA *)&os))
{
char *pszOS = "*";
DWORD dwHandle;
DWORD dwSize = GetFileVersionInfoSizeA("kernel32.dll", &dwHandle);
if (dwSize)
{
LPBYTE lpVersionData = (LPBYTE)malloc(dwSize);
if (GetFileVersionInfoA("kernel32.dll", dwHandle, dwSize, (void**)lpVersionData) != 0)
{
UINT nQuerySize;
DWORD* pdwTransTable;
if (VerQueryValueA(lpVersionData, "\\VarFileInfo\\Translation", (void **)&pdwTransTable, &nQuerySize))
{
DWORD dwLangCharset = MAKELONG(HIWORD(pdwTransTable[0]), LOWORD(pdwTransTable[0]));
char szBlockName[64] = { 0 };
LPVOID lpData;
sprintf_s(szBlockName, sizeof(szBlockName), "\\StringFileInfo\\%08lx\\FileVersion", dwLangCharset);
if (VerQueryValueA(lpVersionData, szBlockName, &lpData, &nQuerySize))
{
os.dwMajorVersion = atoi((const char*)lpData);
if (strchr((char*)lpData, '.'))
{
os.dwMinorVersion = atoi(strchr((char*)lpData, '.') + 1);
if (strchr(strchr((char*)lpData, '.') + 1, '.'))
{
os.dwBuildNumber = atoi(strchr(strchr((char*)lpData, '.') + 1, '.') + 1);
}
}
}
}
}
if (lpVersionData)
{
free(lpVersionData);
}
}
char szOS[32] = { 0 };
char szOSVersion[16] = { 0 };
switch (os.dwPlatformId)
{
case VER_PLATFORM_WIN32_NT:
if (os.dwMajorVersion <= 4)
pszOS = "Windows NT";
if (os.dwMajorVersion == 5 && os.dwMinorVersion == 0)
pszOS = "Windows 2000";
if (os.dwMajorVersion == 5 && os.dwMinorVersion == 1)
pszOS = "Windows XP";
if (os.dwMajorVersion == 5 && os.dwMinorVersion == 2 && os.wProductType == VER_NT_WORKSTATION && si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64)
pszOS = "Windows XP x64 Edition";
if (os.dwMajorVersion == 5 && os.dwMinorVersion == 2 && GetSystemMetrics(SM_SERVERR2) == 0)
pszOS = "Windows Server 2003";
if (os.dwMajorVersion == 5 && os.dwMinorVersion == 2 && (os.wSuiteMask & VER_SUITE_WH_SERVER))
pszOS = "Windows Home Server";
if (os.dwMajorVersion == 5 && os.dwMinorVersion == 2 && GetSystemMetrics(SM_SERVERR2) != 0)
pszOS = "Windows Server 2003R2";
if (os.dwMajorVersion == 6 && os.dwMinorVersion == 0 && os.wProductType == VER_NT_WORKSTATION)
pszOS = "Windows Vista";
if (os.dwMajorVersion == 6 && os.dwMinorVersion == 0 && os.wProductType != VER_NT_WORKSTATION)
pszOS = "Windows Server 2008";
if (os.dwMajorVersion == 6 && os.dwMinorVersion == 1 && os.wProductType != VER_NT_WORKSTATION)
pszOS = "Windows Server 2008R2";
if (os.dwMajorVersion == 6 && os.dwMinorVersion == 1 && os.wProductType == VER_NT_WORKSTATION)
pszOS = "Windows 7";
if (os.dwMajorVersion == 6 && os.dwMinorVersion == 2 && os.wProductType != VER_NT_WORKSTATION)
pszOS = "Windows Server 2012";
if (os.dwMajorVersion == 6 && os.dwMinorVersion == 2 && os.wProductType == VER_NT_WORKSTATION)
pszOS = "Windows 8";
if (os.dwMajorVersion == 6 && os.dwMinorVersion == 3 && os.wProductType != VER_NT_WORKSTATION)
pszOS = "Windows Server 2012R2";
if (os.dwMajorVersion == 6 && os.dwMinorVersion == 3 && os.wProductType == VER_NT_WORKSTATION)
pszOS = "Windows 8.1";
if (os.dwMajorVersion == 10)
pszOS = "Windows 10";
if (os.wServicePackMajor != 0)
{
sprintf_s(szOS, "%s.SP%d", pszOS, os.wServicePackMajor);
}
else
{
sprintf_s(szOS, "%s", pszOS);
}
sprintf_s(pszBuildVersion, nBuildSize, "Build %d", os.dwBuildNumber);
break;
default:
sprintf_s(szOS, "*");
break;
}
memcpy(pszOSVersion, szOS, strlen(szOS));
return TRUE;
}
return TRUE;
}
需要注意的是:
GetVersionEx 函数在VS新版中x64模式下已被废弃,需要加入 #pragma warning(disable: 4996)
屏蔽废弃。
此外,GetVersionEx 系列函数的使用需要添加 #pragma comment(lib,"version.lib")
。