Get OS in c++ win32 for all versions of win?
How to get the OS vers开发者_如何学Pythonion for all windows, at least the name for win95,98,me,xp,vista,7?
Im using visual c++ 2010 and I want to include this feature in a pure win32 app.
How about something like this:
#include <windows.h>
#include <string>
#include <lm.h>
#pragma comment(lib, "netapi32.lib")
bool GetWinMajorMinorVersion(DWORD& major, DWORD& minor)
{
bool bRetCode = false;
LPBYTE pinfoRawData = 0;
if (NERR_Success == NetWkstaGetInfo(NULL, 100, &pinfoRawData))
{
WKSTA_INFO_100* pworkstationInfo = (WKSTA_INFO_100*)pinfoRawData;
major = pworkstationInfo->wki100_ver_major;
minor = pworkstationInfo->wki100_ver_minor;
::NetApiBufferFree(pinfoRawData);
bRetCode = true;
}
return bRetCode;
}
std::string GetWindowsVersionString()
{
std::string winver;
OSVERSIONINFOEX osver;
SYSTEM_INFO sysInfo;
typedef void(__stdcall *GETSYSTEMINFO) (LPSYSTEM_INFO);
__pragma(warning(push))
__pragma(warning(disable:4996))
memset(&osver, 0, sizeof(osver));
osver.dwOSVersionInfoSize = sizeof(osver);
GetVersionEx((LPOSVERSIONINFO)&osver);
__pragma(warning(pop))
DWORD major = 0;
DWORD minor = 0;
if (GetWinMajorMinorVersion(major, minor))
{
osver.dwMajorVersion = major;
osver.dwMinorVersion = minor;
}
else if (osver.dwMajorVersion == 6 && osver.dwMinorVersion == 2)
{
OSVERSIONINFOEXW osvi;
ULONGLONG cm = 0;
cm = VerSetConditionMask(cm, VER_MINORVERSION, VER_EQUAL);
ZeroMemory(&osvi, sizeof(osvi));
osvi.dwOSVersionInfoSize = sizeof(osvi);
osvi.dwMinorVersion = 3;
if (VerifyVersionInfoW(&osvi, VER_MINORVERSION, cm))
{
osver.dwMinorVersion = 3;
}
}
GETSYSTEMINFO getSysInfo = (GETSYSTEMINFO)GetProcAddress(GetModuleHandle(L"kernel32.dll"), "GetNativeSystemInfo");
if (getSysInfo == NULL) getSysInfo = ::GetSystemInfo;
getSysInfo(&sysInfo);
if (osver.dwMajorVersion == 10 && osver.dwMinorVersion >= 0 && osver.wProductType != VER_NT_WORKSTATION) winver = "Windows 10 Server";
if (osver.dwMajorVersion == 10 && osver.dwMinorVersion >= 0 && osver.wProductType == VER_NT_WORKSTATION) winver = "Windows 10";
if (osver.dwMajorVersion == 6 && osver.dwMinorVersion == 3 && osver.wProductType != VER_NT_WORKSTATION) winver = "Windows Server 2012 R2";
if (osver.dwMajorVersion == 6 && osver.dwMinorVersion == 3 && osver.wProductType == VER_NT_WORKSTATION) winver = "Windows 8.1";
if (osver.dwMajorVersion == 6 && osver.dwMinorVersion == 2 && osver.wProductType != VER_NT_WORKSTATION) winver = "Windows Server 2012";
if (osver.dwMajorVersion == 6 && osver.dwMinorVersion == 2 && osver.wProductType == VER_NT_WORKSTATION) winver = "Windows 8";
if (osver.dwMajorVersion == 6 && osver.dwMinorVersion == 1 && osver.wProductType != VER_NT_WORKSTATION) winver = "Windows Server 2008 R2";
if (osver.dwMajorVersion == 6 && osver.dwMinorVersion == 1 && osver.wProductType == VER_NT_WORKSTATION) winver = "Windows 7";
if (osver.dwMajorVersion == 6 && osver.dwMinorVersion == 0 && osver.wProductType != VER_NT_WORKSTATION) winver = "Windows Server 2008";
if (osver.dwMajorVersion == 6 && osver.dwMinorVersion == 0 && osver.wProductType == VER_NT_WORKSTATION) winver = "Windows Vista";
if (osver.dwMajorVersion == 5 && osver.dwMinorVersion == 2 && osver.wProductType == VER_NT_WORKSTATION
&& sysInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) winver = "Windows XP x64";
if (osver.dwMajorVersion == 5 && osver.dwMinorVersion == 2) winver = "Windows Server 2003";
if (osver.dwMajorVersion == 5 && osver.dwMinorVersion == 1) winver = "Windows XP";
if (osver.dwMajorVersion == 5 && osver.dwMinorVersion == 0) winver = "Windows 2000";
if (osver.dwMajorVersion < 5) winver = "unknown";
if (osver.wServicePackMajor != 0)
{
std::string sp;
char buf[128] = { 0 };
sp = " Service Pack ";
sprintf_s(buf, sizeof(buf), "%hd", osver.wServicePackMajor);
sp.append(buf);
winver += sp;
}
return winver;
}
Use GetVersionEx
http://msdn.microsoft.com/en-us/library/ms724451%28v=VS.85%29.aspx
I had a similar problem. Here is some code with Win 11 support. It won't work for server versions, but it is easy to implement add this feature (just another mapping for servers).
// To Workaround Win 10 problem for User Mode VerifyVersionInfo
bool VerifyWindowsVersionInfo(PRTL_OSVERSIONINFOEXW versionInfo, ULONG typeMask, ULONGLONG conditionMask)
{
HMODULE hMod = nullptr;
if ((TRUE != ::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, L"ntdll.dll", &hMod)) || !hMod)
return false;
typedef NTSTATUS(WINAPI* _RtlVerifyVersionInfo)(PRTL_OSVERSIONINFOEXW, ULONG, ULONGLONG);
const auto RtlVerifyVersionInfo =
reinterpret_cast<_RtlVerifyVersionInfo>(::GetProcAddress(hMod, "RtlVerifyVersionInfo"));
if (!RtlVerifyVersionInfo)
return false;
return NT_SUCCESS(RtlVerifyVersionInfo(versionInfo, typeMask, conditionMask));
}
bool IsWindowsVersionOrGreater(int wMajorVersion, int wMinorVersion, int wBuildNumber, int wServicePackMajor)
{
RTL_OSVERSIONINFOEXW osvi = { sizeof(osvi), 0, 0, 0, 0, {0}, 0, 0 };
osvi.dwMajorVersion = wMajorVersion;
osvi.dwMinorVersion = wMinorVersion;
osvi.dwBuildNumber = wBuildNumber;
osvi.wServicePackMajor = static_cast<WORD>(wServicePackMajor);
DWORDLONG dwlConditionMask = 0;
VER_SET_CONDITION(dwlConditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL);
VER_SET_CONDITION(dwlConditionMask, VER_MINORVERSION, VER_GREATER_EQUAL);
VER_SET_CONDITION(dwlConditionMask, VER_BUILDNUMBER, VER_GREATER_EQUAL);
VER_SET_CONDITION(dwlConditionMask, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL);
return VerifyWindowsVersionInfo(&osvi,
VER_MAJORVERSION | VER_MINORVERSION | VER_BUILDNUMBER | VER_SERVICEPACKMAJOR,
dwlConditionMask);
}
std::wstring GetVerbalOsVersion()
{
// see https://msdn.microsoft.com/ru-ru/library/windows/desktop/ms724832(v=vs.85).aspx for details
using OsMajorVersion = int;
using OsMinorVersion = int;
using OsBuildVersion = int;
using OsServicePackMajorVersion = int;
using VersionStrWithNumberPair =
std::pair<std::wstring, std::tuple<OsMajorVersion, OsMinorVersion, OsBuildVersion, OsServicePackMajorVersion>>;
const auto win11BuildNumber = 22000;
const std::vector<VersionStrWithNumberPair> winVersionMapping = {
{L"Windows 11 ",
std::make_tuple(HIBYTE(_WIN32_WINNT_WIN10), LOBYTE(_WIN32_WINNT_WIN10), win11BuildNumber, 0)},
{L"Windows 10 ", std::make_tuple(HIBYTE(_WIN32_WINNT_WIN10), LOBYTE(_WIN32_WINNT_WIN10), 0, 0)},
{L"Windows 8.1", std::make_tuple(HIBYTE(_WIN32_WINNT_WINBLUE), LOBYTE(_WIN32_WINNT_WINBLUE), 0, 0)},
{L"Windows 8 ", std::make_tuple(HIBYTE(_WIN32_WINNT_WIN8), LOBYTE(_WIN32_WINNT_WIN8), 0, 0)},
{L"Windows 7 Service Pack 1", std::make_tuple(HIBYTE(_WIN32_WINNT_WIN7), LOBYTE(_WIN32_WINNT_WIN7), 0, 1)},
{L"Windows 7 ", std::make_tuple(HIBYTE(_WIN32_WINNT_WIN7), LOBYTE(_WIN32_WINNT_WIN7), 0, 0)},
{L"Windows Vista Service Pack 2",
std::make_tuple(HIBYTE(_WIN32_WINNT_VISTA), LOBYTE(_WIN32_WINNT_VISTA), 0, 2)},
{L"Windows Vista Service Pack 1",
std::make_tuple(HIBYTE(_WIN32_WINNT_VISTA), LOBYTE(_WIN32_WINNT_VISTA), 0, 1)},
{L"Windows Vista", std::make_tuple(HIBYTE(_WIN32_WINNT_VISTA), LOBYTE(_WIN32_WINNT_VISTA), 0, 0)},
{L"Windows XP Service Pack 3",
std::make_tuple(HIBYTE(_WIN32_WINNT_WINXP), LOBYTE(_WIN32_WINNT_WINXP), 0, 3)},
{L"Windows XP Service Pack 2",
std::make_tuple(HIBYTE(_WIN32_WINNT_WINXP), LOBYTE(_WIN32_WINNT_WINXP), 0, 2)},
{L"Windows XP Service Pack 1",
std::make_tuple(HIBYTE(_WIN32_WINNT_WINXP), LOBYTE(_WIN32_WINNT_WINXP), 0, 1)},
{L"Windows XP ", std::make_tuple(HIBYTE(_WIN32_WINNT_WINXP), LOBYTE(_WIN32_WINNT_WINXP), 0, 0)} };
const auto it = std::find_if(std::begin(winVersionMapping),
std::end(winVersionMapping),
[](const VersionStrWithNumberPair& el)
{
return IsWindowsVersionOrGreater(std::get<0>(el.second),
std::get<1>(el.second),
std::get<2>(el.second),
std::get<3>(el.second));
});
if (it == std::end(winVersionMapping))
return L"Unknown windows version";
return it->first;
}
Take a look at the MSDN article Getting the System Version
While the article only mentions currently supported Windows versions, see this knowledge base article for the numbers you'll see in the OSVERSIONINFO structure for Win 95, 98 etc.
It all depends on why you need to know OS version:
To use certain feature that may not be available in older OS. In this case I would strongly suggest checking if the API itself is available using LoadLibrary and GetProcAddress functions. Otherwise, I guess you can dynamically import RtlGetVersion from
ntdll.dll
and use it, but again, there're too many ways it can return inaccurate information (the ones that come to mind are compatibility mode and API trampolines that can be installed by malware, AVP, and even OS itself.)For display purposes only. (ex: in
About
window for your app, or to include it in your diagnostic event log, etc.) In this case a quick and easy hack is to read it as text from the System Registry:
The downside of this approach though, is that the names and numbers can be localized for the end-user's system.
Use the following key that is available since Windows XP:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion
and its following REG_SZ
(or string) values:
ProductName
= for OS nameCurrentVersion
= for OS versionBuildLab
= for full build numberBuildLabEx
= extended build number (available since Windows 7)ReleaseId
= Release number (available since Windows 10)
精彩评论