获取Windows版本的正确方法:替代已弃用的GetVersionEx且兼容未来版本
嘿,我完全理解你的需求——要替代已弃用的GetVersionEx,拿到Windows的真实版本信息用来生成报告,而且得兼容Windows 11甚至未来的系统,毕竟GetVersionEx在新系统上会返回假数据,确实挺烦人的。下面这几个靠谱的方法,你可以根据自己的场景选:
方法一:使用RtlGetVersion函数
这个是Windows内核提供的函数,不会受到应用程序兼容性上下文的影响,能返回最原始的系统版本信息。它属于ntdll.dll,可以直接声明调用,也可以动态加载(更稳妥,避免编译依赖问题)。
C++代码示例
#include <windows.h> #include <winternl.h> #include <wchar.h> #pragma comment(lib, "ntdll.lib") // 动态加载的方式(可选,避免编译时依赖ntdll.lib) typedef NTSTATUS(WINAPI* RtlGetVersionFunc)(PRTL_OSVERSIONINFOEXW); BOOL GetRealWindowsVersion(OSVERSIONINFOEXW& osvi) { ZeroMemory(&osvi, sizeof(osvi)); osvi.dwOSVersionInfoSize = sizeof(osvi); // 获取RtlGetVersion函数地址 HMODULE hNtdll = GetModuleHandleW(L"ntdll.dll"); if (!hNtdll) return FALSE; RtlGetVersionFunc pRtlGetVersion = (RtlGetVersionFunc)GetProcAddress(hNtdll, "RtlGetVersion"); if (!pRtlGetVersion) return FALSE; NTSTATUS status = pRtlGetVersion(&osvi); return NT_SUCCESS(status); } // 使用示例 int main() { OSVERSIONINFOEXW osvi; if (GetRealWindowsVersion(osvi)) { wprintf(L"主版本号: %u\n", osvi.dwMajorVersion); wprintf(L"次版本号: %u\n", osvi.dwMinorVersion); wprintf(L"构建号: %u\n", osvi.dwBuildNumber); wprintf(L"产品类型: %u\n", osvi.wProductType); // 划重点:Windows 11的主版本是10,次版本0,构建号≥22000 } return 0; }
这个方法返回的结构和GetVersionEx几乎一致,能轻松拿到你需要的版本参数,未来Windows版本更新后,构建号会持续递增,通过构建号就能区分不同系统版本。
方法二:读取注册表项
这是最通用的方法,几乎所有编程语言都能实现,直接读取Windows系统维护的注册表项,完全不受兼容性设置干扰。需要访问的注册表路径是HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion,里面的关键值涵盖了所有你需要的报告信息:
ProductName:直接显示系统全称(比如“Windows 11 Pro”)CurrentVersion:主版本号(Win10/Win11都是10.0)CurrentBuildNumber:核心构建号(Win10是1904x系列,Win11是22000+)UBR:更新构建版本(比如22621.1265中的1265)ReleaseId:发布分支ID(比如Win11的22H2)
PowerShell示例(快速验证)
$regPath = "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion" $versionData = Get-ItemProperty -Path $regPath Write-Host "系统名称: $($versionData.ProductName)" Write-Host "完整版本: $($versionData.CurrentVersion).$($versionData.CurrentBuildNumber).$($versionData.UBR)" Write-Host "发布分支: $($versionData.ReleaseId)"
C++代码示例
#include <windows.h> #include <string> #include <iostream> std::wstring GetRegistryStringValue(HKEY rootKey, const wchar_t* subKey, const wchar_t* valueName) { HKEY hSubKey; if (RegOpenKeyExW(rootKey, subKey, 0, KEY_READ | KEY_WOW64_64KEY, &hSubKey) != ERROR_SUCCESS) return L""; wchar_t buffer[512]; DWORD bufferSize = sizeof(buffer); DWORD valueType; std::wstring result; if (RegQueryValueExW(hSubKey, valueName, nullptr, &valueType, (LPBYTE)buffer, &bufferSize) == ERROR_SUCCESS && valueType == REG_SZ) { result = buffer; } RegCloseKey(hSubKey); return result; } int main() { std::wstring productName = GetRegistryStringValue(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", L"ProductName"); std::wstring currentVersion = GetRegistryStringValue(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", L"CurrentVersion"); std::wstring buildNumber = GetRegistryStringValue(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", L"CurrentBuildNumber"); std::wstring ubr = GetRegistryStringValue(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", L"UBR"); std::wcout << L"系统名称: " << productName << std::endl; std::wcout << L"完整版本号: " << currentVersion << L"." << buildNumber << L"." << ubr << std::endl; return 0; }
注意:代码里加了KEY_WOW64_64KEY,是为了让32位程序也能读取64位注册表的真实值,避免拿到错误数据。
方法三:读取kernel32.dll的文件版本
系统核心文件kernel32.dll的文件版本就是Windows的真实版本,不会被兼容性策略篡改。可以用Windows的GetFileVersionInfo系列函数来获取。
C++代码示例
#include <windows.h> #include <string> #include <iostream> std::wstring GetKernel32FileVersion() { wchar_t systemDir[MAX_PATH]; GetSystemDirectoryW(systemDir, MAX_PATH); wcscat_s(systemDir, L"\\kernel32.dll"); DWORD dummy; DWORD versionInfoSize = GetFileVersionInfoSizeW(systemDir, &dummy); if (versionInfoSize == 0) return L""; std::vector<BYTE> versionBuffer(versionInfoSize); if (!GetFileVersionInfoW(systemDir, 0, versionInfoSize, versionBuffer.data())) return L""; VS_FIXEDFILEINFO* fileInfo = nullptr; UINT infoSize; if (!VerQueryValueW(versionBuffer.data(), L"\\", (LPVOID*)&fileInfo, &infoSize)) return L""; std::wstring versionStr; versionStr += std::to_wstring(HIWORD(fileInfo->dwFileVersionMS)) + L"."; versionStr += std::to_wstring(LOWORD(fileInfo->dwFileVersionMS)) + L"."; versionStr += std::to_wstring(HIWORD(fileInfo->dwFileVersionLS)) + L"."; versionStr += std::to_wstring(LOWORD(fileInfo->dwFileVersionLS)); return versionStr; } int main() { std::wstring winVersion = GetKernel32FileVersion(); std::wcout << L"Windows真实版本: " << winVersion << std::endl; return 0; }
这个方法获取到的版本号和系统设置里显示的完全一致,比如Win11 22H2会返回10.0.22621.1265这类完整版本字符串。
如果是生成报告,我个人推荐注册表方法,能直接拿到用户友好的系统名称和完整版本信息;如果是在程序里需要版本数值做逻辑处理,RtlGetVersion或者kernel32版本方法都很靠谱。这三个方法都能绕过兼容性限制,返回真实的系统版本,而且会一直兼容未来的Windows版本。
内容的提问来源于stack exchange,提问作者Jabberwocky

