Microsoft于2018年10月2日发布了Windows Server2019。从Windows 2000直到此Windows版本,您可以使用结构GetVersionEx并根据{的变量来调用WinAPI函数OSVERSIONINFOEX {1}},dwMajorVersion
和dwMinorVersion
确定Windows版本,例如Windows 8.1,Windows 10,Windows Server 2012 R2。每个人使用的代码是这样的:
wProductType
从Wikipedia来看,Windows Server 2019具有与Server 2016相同的版本号NT 10.0。因此上述代码不再起作用。
此外,Microsoft Docs包含以下注释: GetVersionEx可能已更改或在Windows 8.1之后的版本中不可用。而是使用版本帮助器功能。
不幸的是,Version Helper functions没有检测Server 2019的功能。而且,奇怪的是,关于Targeting的文档页面在Windows 10上停止运行,而没有谈论服务器版本,这些目标清单对于检测Windows 8.1或Server 2012以上的操作系统是必不可少的。
更新1。
正如@IInspectable和@RbMm评论了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");
}
}
函数的用法。因此,我运行了以下代码(摘自this answer):
RtlGetVersion
这是 Windows 10的结果:
Windows Server 2019:
Update2。。根据要求,发布通过 GetVersionEx 调用从 OSVERSIONINFOEX 结构获得的完整信息,并包含一个清单文件,其中包含所有目标。 Windows 10(请参见上面的“定向”链接):
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;
}
更新3。使用结构// 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
调用RtlGetVersion
会得到与更新2完全相同的结果。
答案 0 :(得分:1)
除了检查MajorVersion
,MinorVersion
和ProductType
,您还必须检查ReleaseId
或BuildNumber
。
ReleaseId: 1809
和BuildNumber: 17763
与 Windows Server 2019 和 Windows Server 1809版的发行版相关联>。因此,通过检查这些数字,您至少应确保自己正在处理
Windows Server 2019 或 Windows Server版本1809(半年通道)(数据中心核心,标准核心)。
请参阅:Windows Server release information
注意: Windows Server 2019的Insider Preview版本可以使ReleaseId 1803或BuildNumbers低于17763。
Microsoft的this thread中的玛丽·霍夫曼说:
ReleaseId
1809与Windows Server 2019和Windows Server相关联, 仅版本1809。 (post)
Windows Server 2016始终为1607。发布产品后, 该ID不会更改。 (post)
遵循该逻辑,Windows Server 2019也将始终为1809
。
您可以从以下注册表项中读取ReleaseId:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion - ReleaseId
请参阅:How to read a value from the Windows registry
内部编号
Windows Server 2019停止在17763。这是最终的主要版本 数字。
vNext版本高于(> = 17764)的任何内容。 (post)
Windows Server 2016始终为10.0.14393。###,其中###递增 安装了累积更新。
Windows Server 2019始终为10.0.17763。###,其中###递增 因为安装了累积更新。 (post)
因此,BuildNumber 17763
应该始终与 Window Server 2019 或 Windows Server版本1809 (或Windows 10 1809)相对应,但是检查ProductType
会告诉您您是服务器)。
答案 1 :(得分:0)
每个新的Windows版本都是相同的故事。再次使用Windows 2019
您应该使用VerifyVersionInfoW ...但同时也会更新程序清单。
问题是:新的Windows版本的清单是什么...
Windows 2016与Windows 10链接的ID为:
请参阅此处:https://docs.microsoft.com/en-us/windows/desktop/sbscs/application-manifests
答案 2 :(得分:0)
根据Windows Server 2019 version info中的讨论:
[Windows] Server 2019数据中心版内部版本17744,ReleaseId字段显示1809。
所以这样的事情应该可以解决问题:
const auto isWinServer2019Plus =
IsWindowsServer() &&
IsWindowsVersionOrGreater(10, 0, 1803);
答案 3 :(得分:0)
我发现的最好方法是使用您提到的GetVersionEx方法,如果该方法返回6.2(对于Windows 8.1及更高版本,它将返回到wmic api)。
下面的代码来自Microsoft,用于使用wmic api获取操作系统名称。
参考:https://docs.microsoft.com/en-us/windows/win32/wmisdk/example--getting-wmi-data-from-the-local-computer
#define _WIN32_DCOM
#include <iostream>
using namespace std;
#include <comdef.h>
#include <Wbemidl.h>
#pragma comment(lib, "wbemuuid.lib")
int main(int argc, char **argv)
{
HRESULT hres;
// Step 1: --------------------------------------------------
// Initialize COM. ------------------------------------------
hres = CoInitializeEx(0, COINIT_MULTITHREADED);
if (FAILED(hres))
{
cout << "Failed to initialize COM library. Error code = 0x"
<< hex << hres << endl;
return 1; // Program has failed.
}
// Step 2: --------------------------------------------------
// Set general COM security levels --------------------------
hres = CoInitializeSecurity(
NULL,
-1, // COM authentication
NULL, // Authentication services
NULL, // Reserved
RPC_C_AUTHN_LEVEL_DEFAULT, // Default authentication
RPC_C_IMP_LEVEL_IMPERSONATE, // Default Impersonation
NULL, // Authentication info
EOAC_NONE, // Additional capabilities
NULL // Reserved
);
if (FAILED(hres))
{
cout << "Failed to initialize security. Error code = 0x"
<< hex << hres << endl;
CoUninitialize();
return 1; // Program has failed.
}
// Step 3: ---------------------------------------------------
// Obtain the initial locator to WMI -------------------------
IWbemLocator *pLoc = NULL;
hres = CoCreateInstance(
CLSID_WbemLocator,
0,
CLSCTX_INPROC_SERVER,
IID_IWbemLocator, (LPVOID *) &pLoc);
if (FAILED(hres))
{
cout << "Failed to create IWbemLocator object."
<< " Err code = 0x"
<< hex << hres << endl;
CoUninitialize();
return 1; // Program has failed.
}
// Step 4: -----------------------------------------------------
// Connect to WMI through the IWbemLocator::ConnectServer method
IWbemServices *pSvc = NULL;
// Connect to the root\cimv2 namespace with
// the current user and obtain pointer pSvc
// to make IWbemServices calls.
hres = pLoc->ConnectServer(
_bstr_t(L"ROOT\\CIMV2"), // Object path of WMI namespace
NULL, // User name. NULL = current user
NULL, // User password. NULL = current
0, // Locale. NULL indicates current
NULL, // Security flags.
0, // Authority (for example, Kerberos)
0, // Context object
&pSvc // pointer to IWbemServices proxy
);
if (FAILED(hres))
{
cout << "Could not connect. Error code = 0x"
<< hex << hres << endl;
pLoc->Release();
CoUninitialize();
return 1; // Program has failed.
}
cout << "Connected to ROOT\\CIMV2 WMI namespace" << endl;
// Step 5: --------------------------------------------------
// Set security levels on the proxy -------------------------
hres = CoSetProxyBlanket(
pSvc, // Indicates the proxy to set
RPC_C_AUTHN_WINNT, // RPC_C_AUTHN_xxx
RPC_C_AUTHZ_NONE, // RPC_C_AUTHZ_xxx
NULL, // Server principal name
RPC_C_AUTHN_LEVEL_CALL, // RPC_C_AUTHN_LEVEL_xxx
RPC_C_IMP_LEVEL_IMPERSONATE, // RPC_C_IMP_LEVEL_xxx
NULL, // client identity
EOAC_NONE // proxy capabilities
);
if (FAILED(hres))
{
cout << "Could not set proxy blanket. Error code = 0x"
<< hex << hres << endl;
pSvc->Release();
pLoc->Release();
CoUninitialize();
return 1; // Program has failed.
}
// Step 6: --------------------------------------------------
// Use the IWbemServices pointer to make requests of WMI ----
// For example, get the name of the operating system
IEnumWbemClassObject* pEnumerator = NULL;
hres = pSvc->ExecQuery(
bstr_t("WQL"),
bstr_t("SELECT * FROM Win32_OperatingSystem"),
WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
NULL,
&pEnumerator);
if (FAILED(hres))
{
cout << "Query for operating system name failed."
<< " Error code = 0x"
<< hex << hres << endl;
pSvc->Release();
pLoc->Release();
CoUninitialize();
return 1; // Program has failed.
}
// Step 7: -------------------------------------------------
// Get the data from the query in step 6 -------------------
IWbemClassObject *pclsObj = NULL;
ULONG uReturn = 0;
while (pEnumerator)
{
HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1,
&pclsObj, &uReturn);
if(0 == uReturn)
{
break;
}
VARIANT vtProp;
// Get the value of the Name property
hr = pclsObj->Get(L"Name", 0, &vtProp, 0, 0);
wcout << " OS Name : " << vtProp.bstrVal << endl;
VariantClear(&vtProp);
pclsObj->Release();
}
// Cleanup
// ========
pSvc->Release();
pLoc->Release();
pEnumerator->Release();
CoUninitialize();
return 0; // Program successfully completed.
}
答案 4 :(得分:0)
唯一的区别是dwBuildNumber。所以这段代码对我有用:
else if (osvi.dwMajorVersion == 10 && osvi.dwMinorVersion == 0)
{
if (osvi.wProductType == VER_NT_WORKSTATION)
m_csOsType += _T("10 ");
else
{
if (osvi.dwBuildNumber >= 17763)
m_csOsType += _T("Server 2019 ");
else
m_csOsType += _T("Server 2016 ");
}
}