#include "CGetOSVersion.h"
/// <summary>读取注册表中的字符串值</summary>
static bool ReadRegString(HKEY root, const char* path, const char* key, std::string& value)
{
HKEY hKey = NULL;
if (RegOpenKeyExA(root, path, 0, KEY_READ, &hKey) != ERROR_SUCCESS) return false;
char buf[512] = { 0 };
DWORD size = sizeof(buf);
DWORD type = 0;
auto rs = RegQueryValueExA(hKey, key, NULL, &type, (LPBYTE)buf, &size);
RegCloseKey(hKey);
if (rs != ERROR_SUCCESS || (type != REG_SZ && type != REG_EXPAND_SZ)) return false;
value = buf;
return true;
}
/// <summary>通过注册表判断是否服务器版操作系统</summary>
static bool IsServerOS()
{
std::string type;
if (!ReadRegString(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\ProductOptions", "ProductType", type)) return false;
return !type.empty() && _stricmp(type.c_str(), "WinNT") != 0;
}
CGetOSVersion::CGetOSVersion()
{
m_Info.Major = 0;
m_Info.Minor = 0;
m_Info.Build = 0;
m_Info.IsServer = false;
m_Info.Is64Bit = false;
m_Info.ServicePack = 0;
}
CGetOSVersion::~CGetOSVersion()
{
}
/// <summary>宽字符串转ANSI字符串</summary>
static std::string WideToAnsi(const wchar_t* str)
{
if (str == NULL || str[0] == 0) return "";
auto len = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
if (len <= 0) return "";
std::string buf(len - 1, '\0');
WideCharToMultiByte(CP_ACP, 0, str, -1, &buf[0], len, NULL, NULL);
return buf;
}
/// <summary>检测本地操作系统版本信息</summary>
/// <returns>操作系统版本信息</returns>
OSVersionInfo CGetOSVersion::GetVersion()
{
CheckOSVer();
return m_Info;
}
/// <summary>内部调用接口,检测本地操作系统版本信息</summary>
/// <returns>bool,值为真则表示检测成功</returns>
bool CGetOSVersion::CheckOSVer()
{
m_Info.Major = 0;
m_Info.Minor = 0;
m_Info.Build = 0;
m_Info.ServicePack = 0;
m_Info.IsServer = IsServerOS();
m_Info.Desc = "未知的系统版本";
auto bExcute = true;
std::string csd;
// Windows 8.1 起 GetVersionEx 受清单影响会撒谎,优先使用 ntdll!RtlGetVersion
typedef LONG(WINAPI* RTLGETVERSION)(OSVERSIONINFOW*);
auto hinst = LoadLibraryA("ntdll.dll");
if (hinst != NULL)
{
auto pfn = (RTLGETVERSION)GetProcAddress(hinst, "RtlGetVersion");
if (pfn != NULL)
{
OSVERSIONINFOW vi;
ZeroMemory(&vi, sizeof(vi));
vi.dwOSVersionInfoSize = sizeof(vi);
if (pfn(&vi) == 0)
{
m_Info.Major = vi.dwMajorVersion;
m_Info.Minor = vi.dwMinorVersion;
m_Info.Build = vi.dwBuildNumber;
csd = WideToAnsi(vi.szCSDVersion);
}
}
FreeLibrary(hinst);
}
if (m_Info.Major == 0)
{
OSVERSIONINFOA vi;
ZeroMemory(&vi, sizeof(vi));
vi.dwOSVersionInfoSize = sizeof(vi);
// GetVersionEx 在新系统中已标记弃用,这里仅作为 RtlGetVersion 不可用时的兜底
#pragma warning(push)
#pragma warning(disable: 4996)
auto success = GetVersionExA(&vi) != FALSE;
#pragma warning(pop)
if (success)
{
m_Info.Major = vi.dwMajorVersion;
m_Info.Minor = vi.dwMinorVersion;
m_Info.Build = vi.dwBuildNumber;
csd = vi.szCSDVersion;
}
else
bExcute = false;
}
// 判断64位系统。32位进程中 GetSystemInfo 只返回当前进程架构,必须使用 GetNativeSystemInfo
SYSTEM_INFO si;
ZeroMemory(&si, sizeof(si));
GetNativeSystemInfo(&si);
m_Info.Is64Bit = si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64 ||
si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64 ||
si.wProcessorArchitecture == (WORD)12; // ARM64
if (bExcute) m_Info.Desc = FormatDesc(m_Info.Major, m_Info.Minor, m_Info.Build, m_Info.IsServer, csd);
// 从 CSDVersion(如 "Service Pack 3")解析 Service Pack 序号
auto ps = csd.find("Service Pack");
if (ps != std::string::npos) m_Info.ServicePack = (DWORD)atoi(csd.c_str() + ps + 12);
return bExcute;
}
/// <summary>根据版本号生成系统描述</summary>
/// <param name="major">主版本号</param>
/// <param name="minor">次版本号</param>
/// <param name="build">构建号</param>
/// <param name="isServer">是否服务器版</param>
/// <param name="csd">服务包描述,如 Service Pack 1</param>
/// <returns>系统描述,如 Windows 7 SP1</returns>
std::string CGetOSVersion::FormatDesc(DWORD major, DWORD minor, DWORD build, bool isServer, const std::string& csd)
{
std::string desc = "未知的系统版本";
if (major == 5)
{
if (minor == 0) desc = "Windows 2000";
else if (minor == 1) desc = "Windows XP";
else if (minor == 2) desc = isServer ? "Windows Server 2003" : "Windows XP x64";
}
else if (major == 6)
{
if (minor == 0) desc = isServer ? "Windows Server 2008" : "Windows Vista";
else if (minor == 1) desc = isServer ? "Windows Server 2008 R2" : "Windows 7";
else if (minor == 2) desc = isServer ? "Windows Server 2012" : "Windows 8";
else if (minor == 3) desc = isServer ? "Windows Server 2012 R2" : "Windows 8.1";
}
else if (major == 10)
{
// Windows 11 与 Server 2022/2025 的主次版本号同样是 10.0,只能靠构建号区分
if (build >= 22000) desc = isServer ? "Windows Server 2022 或更高" : "Windows 11";
else desc = isServer ? "Windows Server 2016/2019" : "Windows 10";
}
if (!csd.empty() && csd != "Service Pack 0")
{
// 描述统一为 Win7 SP1 风格
auto ps = csd.find("Service Pack");
if (ps != std::string::npos) desc += " SP" + csd.substr(ps + 13);
else desc += " " + csd;
}
return desc;
}
|