正确获得Windows版本的姿势

cpp 复制代码
#include<iostream>
#include<string>
#include <windows.h>

// Refer: https://stackoverflow.com/questions/36543301/detecting-windows-10-version/36545162#36545162
typedef LONG NTSTATUS, * PNTSTATUS;
#define STATUS_SUCCESS (0x00000000)

// GetVersionEx 和 VerifyVersionInfo 的底层
// 随着 Windows 8.1 的发布,GetVersionEx API 的行为在操作系统版本返回的值中已更改。 GetVersionEx 函数返回的值现在取决于应用程序的清单方式。
// 未为 Windows 8.1 或 Windows 10 清单的应用程序将返回 Windows 8 OS 版本值(6.2)。
typedef NTSTATUS(WINAPI* RtlGetVersionPtr)(PRTL_OSVERSIONINFOEXW);

RTL_OSVERSIONINFOEXW GetRealOSVersion() {
	HMODULE hMod = ::GetModuleHandleW(L"ntdll.dll");
	if (hMod) {
		RtlGetVersionPtr fxPtr = (RtlGetVersionPtr)::GetProcAddress(hMod, "RtlGetVersion");
		if (fxPtr != nullptr) {
			RTL_OSVERSIONINFOEXW rovi = { 0 };
			rovi.dwOSVersionInfoSize = sizeof(rovi);
			if (STATUS_SUCCESS == fxPtr(&rovi)) {
				return rovi;
			}
		}
	}
	RTL_OSVERSIONINFOEXW rovi = { 0 };
	return rovi;
}

bool OpenRegistryKey(HKEY hKey, const char* szKeyName, HKEY* phKey)
{
	// 打开注册表项
	LONG result = RegOpenKeyEx(
		hKey,
		szKeyName,
		0,
		KEY_READ,
		phKey
	);
	if (result != ERROR_SUCCESS) {
		return false;
	}
	return true;
}

bool GetDisplayVersion(HKEY hKey, char* szDisplayVersion, size_t bufferSize)
{
	// Ref: https://stackoverflow.com/questions/73436713/how-to-get-the-correct-windows-version-from-command-line
	// Apparently only works in version 20H2 and above.

	TCHAR displayVersion[256] = { 0 };
	DWORD regBufferSize = sizeof(displayVersion);
	DWORD valueType;

	// 读取注册表值
	HRESULT result = RegQueryValueEx(
		hKey,
		TEXT("DisplayVersion"),
		nullptr,
		&valueType,
		reinterpret_cast<LPBYTE>(displayVersion),
		&regBufferSize
	);

	if (result == ERROR_SUCCESS && valueType == REG_SZ) {
		strncpy_s(szDisplayVersion, bufferSize, displayVersion, sizeof(displayVersion));
		return true;
	}
	return false;
}

bool GetProductName(HKEY hKey, char* szProductName, size_t bufferSize)
{
	TCHAR productName[256] = { 0 };
	DWORD regBufferSize = sizeof(productName);
	DWORD valueType;
	// 读取注册表值
	HRESULT result = RegQueryValueEx(
		hKey,
		TEXT("ProductName"),
		nullptr,
		&valueType,
		reinterpret_cast<LPBYTE>(productName),
		&regBufferSize
	);
	if (result == ERROR_SUCCESS && valueType == REG_SZ) {
		strncpy_s(szProductName, bufferSize, productName, sizeof(productName));
		return true;
	}
	return false;
}

bool GetCurrentBuildNumber(HKEY hKey, char* szCurrentBuildNumber, size_t bufferSize)
{
	TCHAR currentBuildNumber[256] = { 0 };
	DWORD regBufferSize = sizeof(currentBuildNumber);
	DWORD valueType;
	// 读取注册表值
	HRESULT result = RegQueryValueEx(
		hKey,
		TEXT("CurrentBuildNumber"),
		nullptr,
		&valueType,
		reinterpret_cast<LPBYTE>(currentBuildNumber),
		&regBufferSize
	);
	if (result == ERROR_SUCCESS && valueType == REG_SZ) {
		strncpy_s(szCurrentBuildNumber, bufferSize, currentBuildNumber, sizeof(currentBuildNumber));
		return true;
	}
	return false;
}

bool GetUBR(HKEY hKey, DWORD& ubr) {
	DWORD bufferSize = sizeof(DWORD);
	DWORD valueType;

	// 读取注册表值
	LONG result = RegQueryValueEx(
		hKey,
		TEXT("UBR"),
		nullptr,
		&valueType,
		reinterpret_cast<LPBYTE>(&ubr),
		&bufferSize
	);

	if (result == ERROR_SUCCESS && valueType == REG_DWORD) {
		return true;
	}
	return false;
}

// Ref: https://stackoverflow.com/questions/69373447/is-there-an-official-way-to-detect-windows-11
// Convert from: https://en.wikipedia.org/wiki/List_of_Microsoft_Windows_versions
// 这里有更加简洁的 https://www.gaijin.at/en/infos/windows-version-numbers
// 这里有更多的 https://www.gaijin.at/en/infos/windows-version-numbers
#include<map>
#include<string>
class WindowsVersions {
public:
	static std::map<int, std::string> getWindowsVersions() {
		std::map<int, std::string> windowsVersions;

		// Non-NT Windows versions
		windowsVersions[102] = "Windows for Workgroups 3.1";
		windowsVersions[103] = "Windows 3.1";
		windowsVersions[153] = "Windows 3.2";
		windowsVersions[300] = "Windows for Workgroups 3.11";

		// NT-based Windows versions
		windowsVersions[511] = "Windows NT 3.1";
		windowsVersions[528] = "Windows NT 3.1 Service Pack 3";
		windowsVersions[807] = "Windows NT 3.5";
		windowsVersions[950] = "Windows 95";
		windowsVersions[1057] = "Windows NT 3.51 Workstation";
		windowsVersions[1381] = "Windows NT 4.0 Workstation";
		windowsVersions[1998] = "Windows 98";
		windowsVersions[2195] = "Windows 2000 Professional";
		windowsVersions[2222] = "Windows 98 Second Edition";
		windowsVersions[2600] = "Windows XP";
		windowsVersions[2700] = "Windows XP Media Center Edition 2005";
		windowsVersions[2710] = "Windows XP Media Center Edition 2005 Update Rollup 2";
		windowsVersions[3000] = "Windows Me";
		windowsVersions[3790] = "Windows XP Professional x64 Edition/Windows Server 2003";
		windowsVersions[6000] = "Windows Vista/Windows Server 2008";
		windowsVersions[6001] = "Windows Vista/Windows Server 2008 Service Packs 1";
		windowsVersions[6002] = "Windows Vista, Service Pack 2";//Windows Vista and Windows Server 2008 originally had the build number 6000 when they were first released; the build number was increased by one with each of the two subsequent Service Packs.
		windowsVersions[6003] = "Windows Server 2008 Service Pack 2, Rollup KB4489887";
		windowsVersions[7600] = "Windows 7";
		windowsVersions[7601] = "Windows 7, Service Pack 1";// Windows 7 and Windows Server 2008 R2 originally had the build number 7600 when they were first released; the build number was increased to 7601 with the release of Service Pack 1.
		windowsVersions[8400] = "Windows Home Server 2011";
		windowsVersions[9200] = "Windows 8/Windows Server 2012";
		windowsVersions[9600] = "Windows 8.1";
		windowsVersions[10240] = "Windows 10 version 1507";
		windowsVersions[10586] = "Windows 10 version 1511";
		windowsVersions[14393] = "Windows 10 version 1607";
		windowsVersions[15063] = "Windows 10 version 1703";
		windowsVersions[16299] = "Windows 10 version 1709";
		windowsVersions[17134] = "Windows 10 version 1803";
		windowsVersions[17763] = "Windows 10 version 1809";
		windowsVersions[18362] = "Windows 10 version 1903";
		windowsVersions[18363] = "Windows 10 version 1909";
		windowsVersions[19041] = "Windows 10 version 2004";
		windowsVersions[19042] = "Windows 10 version 20H2";
		windowsVersions[19043] = "Windows 10 version 21H1";
		windowsVersions[19044] = "Windows 10 version 21H2";
		windowsVersions[19045] = "Windows 10 version 22H2";
		windowsVersions[20348] = "Windows Server 2022 21H2";
		windowsVersions[22000] = "Windows 11 21H2";
		windowsVersions[22621] = "Windows 11 22H2";
		windowsVersions[22631] = "Windows 11 23H2";
		windowsVersions[25398] = "Windows Server 23H2";
		windowsVersions[26100] = "Windows 11 24H2";
		return windowsVersions;
	}
};


int main()
{
	// Ref: https://stackoverflow.com/questions/36543301/detecting-windows-10-version/36545162#36545162
	HKEY hKey;
	// 打开注册表项
	if (!OpenRegistryKey(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", &hKey)) {
		return 1;
	}
	// DisplayVersion
	char szDisplayVersion[256];
	if (GetDisplayVersion(hKey, szDisplayVersion, sizeof(szDisplayVersion))) {
		printf("DisplayVersion: %s\n", szDisplayVersion); // 22H2之类的版本号
	}

	// ProductName
	char szProductName[256];
	if (GetProductName(hKey, szProductName, sizeof(szDisplayVersion))) {
		printf("ProductName: %s\n", szProductName); // 产品名,不准确 比如Windows11 显示的是Windows 10;Windows 8显示的是Windows 6.2
		// 此外还有很多用户拿到的系统ProductName为Windows3.1,但是GetVersionEx获取到的为Windows 6.1 Service Pack 1,推测系统为Windows 7 SP1
		// 同样的,有ProductName为Windows Sever 2000的玩家,但是GetVersionEx获取到的为Windows 6.1 Service Pack 1
		// 因此注册表不准确
	}

	// CurrentBuildNumber
	char szCurrentBuildNumber[256];
	if (GetCurrentBuildNumber(hKey, szCurrentBuildNumber, sizeof(szCurrentBuildNumber))) {
		printf("CurrentBuildNumber: %s\n", szCurrentBuildNumber);
	}

	// UBR
	DWORD ubr = 0;
	if (GetUBR(hKey, ubr)) {
		printf("UBR: %d\n", ubr); // 更新组件版本
		// 核心组件版本不同,Windows Containers 基底映像 (Base Image) 的相容性不同。
		// 更新組建版本不同,不影響 Windows Containers 執行,只差在安全性與功能修正而已,不牽涉核心調整。
		// Ref https://blog.miniasp.com/post/2019/04/02/Understanding-Windows-OS-versioning
	}

	// GetVersionEx
	OSVERSIONINFO osvi;

	ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
	osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
	GetVersionEx(&osvi);
	printf("GetVersionEx: Version is %d.%d (%d:%s)\n",
		osvi.dwMajorVersion, // 主版本
		osvi.dwMinorVersion, // 次版本
		osvi.dwBuildNumber, // 核心组件版本
		osvi.szCSDVersion); // Service Pack


	// Build Number在注册表中拿到信息可能不正确

	// RtlGetVersionPtr
	RTL_OSVERSIONINFOEXW osInfo = GetRealOSVersion();
	if (osInfo.dwOSVersionInfoSize != 0)
	{
		if (wcscmp(osInfo.szCSDVersion, L"") == 0)
			printf("RtlGetVersionPtr: Version is %d.%d (%d)\n",
				osInfo.dwMajorVersion, // 主版本
				osInfo.dwMinorVersion, // 次版本
				osInfo.dwBuildNumber); // 核心组件版本
		else
			printf("RtlGetVersionPtr: Version is %d.%d (%d:%ws)\n",
				osInfo.dwMajorVersion, // 主版本
				osInfo.dwMinorVersion, // 次版本
				osInfo.dwBuildNumber, // 核心组件版本
				osInfo.szCSDVersion); // Service Pack

		// OS Version
		int currentBuildNumber = osInfo.dwBuildNumber;
		std::map<int, std::string> windowsVersions = WindowsVersions::getWindowsVersions();
		auto it = windowsVersions.find(currentBuildNumber);
		if (it != windowsVersions.end()) {
			printf("Windows Version: %s\n", it->second.c_str());
		}
	}
	// 关闭注册表项
	RegCloseKey(hKey);

	getchar();

	return 0;
}
相关推荐
点云SLAM1 小时前
C++内存泄漏检测之Windows 专用工具(CRT Debug、Dr.Memory)和Linux 专业工具(ASan 、heaptrack)
linux·c++·windows·asan·dr.memory·c++内存泄漏检测·c++内存管理
浅念-1 小时前
C语言小知识——指针(3)
c语言·开发语言·c++·经验分享·笔记·学习·算法
LuiChun1 小时前
Docker Compose 容器服务查询与文件查看操作指南(Windows Docker Desktop 版)【一】
linux·运维·windows·docker·容器
无限进步_3 小时前
【C++】大数相加算法详解:从字符串加法到内存布局的思考
开发语言·c++·windows·git·算法·github·visual studio
C+-C资深大佬3 小时前
C++ 数据类型转换是如何实现的?
开发语言·c++·算法
love530love3 小时前
彻底解决 ComfyUI Mixlab 插件 Whisper.available False 的报错
人工智能·windows·python·whisper·win_comfyui
习惯就好zz4 小时前
[实战笔记] 从 Qt 5.12.9 跨越到 Qt 6.x 完美迁移指南 (Windows + VS)
windows·qt·msvc·qt5·qt6·迁移
石像鬼₧魂石4 小时前
Windows Server 2003 域控制器靶机搭建与渗透环境配置手册
linux·windows·学习
oioihoii5 小时前
回归测试:软件演进中的质量守护神与实践全指南
c++
抠头专注python环境配置5 小时前
解决“No module named ‘tensorflow‘”报错:从导入失败到环境配置成功
人工智能·windows·python·tensorflow·neo4j