マイクロソフトは2018年10月2日にWindows Server 2019をリリースしました。Windows2000以降、このWindowsバージョンまで、WinAPI関数 GetVersionEx を構造体 [〜#〜] osversioninfoex [〜 #〜] およびdwMajorVersion
、dwMinorVersion
とwProductType
の変数に応じて、Windowsのバージョンを決定します。たとえば、Windows 8.1、Windows 10、Windows Server 2012 R2。誰もが使用したコードは次のようなものでした:
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");
}
}
Wikipedia から判断すると、Windows Server 2019のバージョン番号はNT 10.0でServer 2016と同じです。そのため、上記のコードは動作しなくなりました。
また、Microsoft Docsには次のメモが含まれています:GetVersionExが変更されているか、Windows 8.1以降のリリースでは使用できない場合があります。代わりに、バージョンヘルパー関数を使用してください。
残念ながら、 Version Helper functions にはサーバー2019を検出する機能がありません。また、奇妙なことに Targeting に関するドキュメントページがWindows 10で停止し、サーバーエディションについて説明しますが、これらのターゲティングマニフェストは、Windows 8.1またはServer 2012以上のOSを検出するために必須です。
Update 1。@IInspectableおよび@RbMmがRtlGetVersion
関数の使用についてコメントしたため。それで、私は次のコードを実行しました( この答え から取得):
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;
}
そして、これがWindows 10の結果です:
Windows Server 2019:
Update2。要求に応じて、[〜#〜] osversioninfoex [〜#〜]Windows 10までのすべてのターゲットを含むマニフェストファイルでGetVersionEx呼び出しを介して取得された構造体(上記のターゲットリンクを参照):
// 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。struct RTL_OSVERSIONINFOEXW
でRtlGetVersion
を呼び出すと、Update 2とまったく同じ結果が得られます。
Windows Server 2019バージョン情報 の議論によると:
[Windows] Server 2019 Datacenter Editionビルド17744、ReleaseIdフィールドに1809が表示されます。
したがって、次のようなものがうまくいくはずです。
const auto isWinServer2019Plus =
IsWindowsServer() &&
IsWindowsVersionOrGreater(10, 0, 1803);
MajorVersion
、MinorVersion
、およびProductType
のチェックとは別に、ReleaseId
またはBuildNumber
もチェックする必要があります。
ReleaseId: 1809
およびBuildNumber: 17763
はリリースバージョンのWindows Server 2019およびに関連付けられていますWindows Server、バージョン1809。したがって、これらの数値を確認することで、少なくともWindows Server 2019またはWindows Server、version 1809(Semi- Annual Channel)(Datacenter Core、Standard Core)。
Windows Server 2019のInsider Previewビルドは、ReleaseId 1803または17763未満のビルド番号を持つことができます。
this thread MicrosoftのMary Hoffmanはこう言っています:
ReleaseId
1809は、Windows Server 2019およびWindows Serverバージョン1809にのみ関連付けられています。 リンク
Windows Server 2016は常に1607です。製品がリリースされると、そのIDは変更されません。 リンク
したがって、Windows Server 2019も常に1809
。
レジストリからReleaseIdを読み取ります。HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion - ReleaseId
BuildNumber
Windows Server 2019は17763で終了します。これが最後のメジャービルド番号です。
それより高いもの(> = 17764)はvNextビルドになります。 リンク
Windows Server 2016は常に10.0.14393。###です。###は、累積的な更新プログラムがインストールされると増加します。
Windows Server 2019は常に10.0.17763。###になります。累積的な更新がインストールされると、###は増加します。 リンク
そう BuildNumber 17763
は常にWindow Server 2019またはWindows Server、version 1809(またはWindows 10 1809に対応する必要がありますが、ProductType
はサーバーかどうかを示します)。
私が見つけた最良の方法は、あなたが言及したGetVersionExメソッドを使用することです。それが6.2(Windows 8.1以上の場合)を返す場合、wmic apiにフォールバックします。
wmic apiを使用してOS名を取得するためにMicrosoftから取得した以下のコード。
参照: 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.
}