Microsoft released Windows Server 2019 on October 2, 2018. From Windows 2000 and up until this Windows version, you could call a WinAPI function GetVersionEx with a struct OSVERSIONINFOEX and depending on the variables of dwMajorVersion
, dwMinorVersion
and wProductType
determine Windows version, for example, Windows 8.1, Windows 10, Windows Server 2012 R2. The code everyone used was something like this:
OSVERSIONINFOEX osvi;
SecureZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
if (GetVersionEx(&osvi)) {
if (osvi.dwMajorVersion == 10 &&
osvi.dwMinorVersion == 0 &&
osvi.wProductType != VER_NT_WORKSTATION) {
Console->Log("We are running on Windows Server 2016");
}
}
Judging from Wikipedia the Windows Server 2019 has the same version number of NT 10.0 as Server 2016. So the above code does not work anymore.
Also, Microsoft Docs contains the following note: GetVersionEx may be altered or unavailable for releases after Windows 8.1. Instead, use the Version Helper functions.
Unfortunately, the Version Helper functions does not have a function to detect Server 2019. Also, the strange thing is that Docs page about Targeting stops at the Windows 10, and does not talk about Server editions, while these Targeting manifests is mandatory for detecting OS above Windows 8.1 or Server 2012.
Update 1.
As @IInspectable and @RbMm commented about usage of RtlGetVersion
function. So I ran the following code (taken from this answer):
typedef LONG NTSTATUS, *PNTSTATUS;
#define STATUS_SUCCESS (0x00000000)
typedef NTSTATUS (WINAPI* RtlGetVersionPtr)(PRTL_OSVERSIONINFOW);
RTL_OSVERSIONINFOW GetRealOSVersion() {
HMODULE hMod = ::GetModuleHandleW(L"ntdll.dll");
if (hMod) {
RtlGetVersionPtr fxPtr = (RtlGetVersionPtr)::GetProcAddress(hMod, "RtlGetVersion");
if (fxPtr != nullptr) {
RTL_OSVERSIONINFOW rovi = { 0 };
rovi.dwOSVersionInfoSize = sizeof(rovi);
if ( STATUS_SUCCESS == fxPtr(&rovi) ) {
return rovi;
}
}
}
RTL_OSVERSIONINFOW rovi = { 0 };
return rovi;
}
And here are the results for Windows 10:
- dwMajorVersion = 10
- dwMinorVersion = 0
- dwBuildNumber = 17134
- dwPlatformId = 2
Windows Server 2019:
- dwMajorVersion = 10
- dwMinorVersion = 0
- dwBuildNumber = 17763
- dwPlatformId = 2
Update2. As requested, posting full info from OSVERSIONINFOEX struct that was obtained via GetVersionEx call with a manifest file containing all the Targets till Windows 10 (see the Targeting link above):
// Windows 10
osvi.dwOSVersionInfoSize = 284
osvi.dwMajorVersion = 10
osvi.dwMinorVersion = 0
osvi.dwBuildNumber = 17134
osvi.dwPlatformId = 2
osvi.szCSDVersion =
osvi.wServicePackMinor = 0
osvi.wServicePackMinor = 0
osvi.wSuiteMask = 256 // 0x100
osvi.wProductType = 1
osvi.wReserved = 0
// Windows Server 2016
osvi.dwOSVersionInfoSize = 284
osvi.dwMajorVersion = 10
osvi.dwMinorVersion = 0
osvi.dwBuildNumber = 14393
osvi.dwPlatformId = 2
osvi.szCSDVersion =
osvi.wServicePackMinor = 0
osvi.wServicePackMinor = 0
osvi.wSuiteMask = 400
osvi.wProductType = 3
osvi.wReserved = 0
// Windows Server 2019
osvi.dwOSVersionInfoSize = 284
osvi.dwMajorVersion = 10
osvi.dwMinorVersion = 0
osvi.dwBuildNumber = 17763
osvi.dwPlatformId = 2
osvi.szCSDVersion =
osvi.wServicePackMinor = 0
osvi.wServicePackMinor = 0
osvi.wSuiteMask = 400 // 0x190
osvi.wProductType = 3
osvi.wReserved = 0
Update 3. Calling RtlGetVersion
with a struct RTL_OSVERSIONINFOEXW
we get exactly the same result as in Update 2.