正确获得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;
}
相关推荐
qdprobot1 小时前
Mixly米思齐1.0 2.0 3.0 软件windows版本MAC苹果电脑系统安装使用常见问题与解决
windows·macos
可涵不会debug3 小时前
【C++】在线五子棋对战项目网页版
linux·服务器·网络·c++·git
AI+程序员在路上3 小时前
C#调用c++dll的两种方法(静态方法和动态方法)
c++·microsoft·c#
chengxuyuan666663 小时前
python基础语句整理
java·windows·python
mit6.8243 小时前
What is Json?
c++·学习·json
灶龙4 小时前
浅谈 PID 控制算法
c++·算法
菜还不练就废了4 小时前
蓝桥杯算法日常|c\c++常用竞赛函数总结备用
c++·算法·蓝桥杯
新知图书5 小时前
Linux C\C++编程-文件位置指针与读写文件数据块
linux·c语言·c++
qystca5 小时前
异或和之和
数据结构·c++·算法·蓝桥杯