web-dev-qa-db-ja.com

C ++ Windows Server 2019を検出する方法は?

マイクロソフトは2018年10月2日にWindows Server 2019をリリースしました。Windows2000以降、このWindowsバージョンまで、WinAPI関数 GetVersionEx を構造体 [〜#〜] osversioninfoex [〜 #〜] およびdwMajorVersiondwMinorVersionwProductTypeの変数に応じて、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の結果です:

  • dwMajorVersion = 10
  • dwMinorVersion = 0
  • dwBuildNumber = 17134
  • dwPlatformId = 2

Windows Server 2019:

  • dwMajorVersion = 10
  • dwMinorVersion = 0
  • dwBuildNumber = 17763
  • dwPlatformId = 2

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_OSVERSIONINFOEXWRtlGetVersionを呼び出すと、Update 2とまったく同じ結果が得られます。

11
Maris B.

Windows Server 2019バージョン情報 の議論によると:

[Windows] Server 2019 Datacenter Editionビルド17744、ReleaseIdフィールドに1809が表示されます。

したがって、次のようなものがうまくいくはずです。

const auto isWinServer2019Plus =
  IsWindowsServer() &&
  IsWindowsVersionOrGreater(10, 0, 1803);
0
NuSkooler

MajorVersionMinorVersion、および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のリリース情報

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

参照: Windowsレジストリから値を読み取る方法

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はサーバーかどうかを示します)。

0
fridoo

私が見つけた最良の方法は、あなたが言及した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.

}
0
Mayank R