web-dev-qa-db-fra.com

C ++ Comment détecter Windows Server 2019?

Microsoft a publié Windows Server 2019 le 2 octobre 2018. De Windows 2000 et jusqu'à cette version de Windows, vous pouvez appeler une fonction WinAPI GetVersionEx avec une structure OSVERSIONINFOEX et selon les variables de dwMajorVersion, dwMinorVersion et wProductType déterminent la version de Windows, par exemple, Windows 8.1, Windows 10, Windows Server 2012 R2. Le code que tout le monde a utilisé était quelque chose comme ceci:

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");
        }
}

A en juger par Wikipedia , Windows Server 2019 a le même numéro de version de NT 10.0 que Server 2016. Donc, le code ci-dessus ne fonctionne plus.

En outre, Microsoft Docs contient la note suivante: GetVersionEx peut être modifié ou indisponible pour les versions après Windows 8.1. Utilisez plutôt les fonctions Version Helper.

Malheureusement, le fonctions de Version Helper n'a pas de fonction pour détecter le serveur 2019. De plus, la chose étrange est que la page Docs sur Ciblage s'arrête sur Windows 10 et ne le fait pas parler des éditions du serveur, tandis que ces manifestes de ciblage sont obligatoires pour détecter le système d'exploitation au-dessus de Windows 8.1 ou Server 2012.

Mise à jour 1. Comme @IInspectable et @RbMm ont commenté l'utilisation de la fonction RtlGetVersion. J'ai donc exécuté le code suivant (tiré de cette réponse ):

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;
}

Et voici les résultats pour Windows 10:

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

Windows Server 2019:

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

Update2. Comme demandé, publier toutes les informations de [~ # ~] osversioninfoex [~ # ~] struct qui a été obtenu via GetVersionEx appel avec un fichier manifeste contenant toutes les cibles jusqu'à Windows 10 (voir le lien Ciblage ci-dessus):

// 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

Mise à jour 3. Appel de RtlGetVersion avec une structure RTL_OSVERSIONINFOEXW nous obtenons exactement le même résultat que dans la mise à jour 2.

11
Maris B.

Selon les discussions dans Informations sur la version de Windows Server 2019 :

[Windows] Server 2019 Datacenter Edition build 17744, le champ ReleaseId affiche 1809.

Donc, quelque chose comme ça devrait faire l'affaire:

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

Outre la vérification de MajorVersion, MinorVersion et ProductType, vous devez également vérifier ReleaseId ou BuildNumber.

ReleaseId: 1809 et BuildNumber: 17763 sont associés aux versions de publication de Windows Server 2019 et Windows Server, version 1809. Donc, en vérifiant ces chiffres, vous devez au moins être sûr que vous traitez avec Windows Server 2019 ou Windows Server, version 1809 (canal semi-annuel) (Datacenter Core , Standard Core).

Voir: Informations de version de Windows Server

Les versions Insider Preview de Windows Server 2019 peuvent avoir ReleaseId 1803 ou BuildNumbers en dessous de 17763.


Dans ce fil Mary Hoffman de Microsoft dit:

ReleaseId

1809 est associé à Windows Server 2019 et Windows Server, version 1809 uniquement. lien

Windows Server 2016 sera toujours 1607. Une fois le produit publié, cet ID ne changera pas. lien

Donc, je suppose que Windows Server 2019 sera également toujours 1809.

Lisez le ReleaseId du registre:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion - ReleaseId

Voir: Comment lire une valeur du registre Windows

BuildNumber

Windows Server 2019 s'arrête à 17763. C'était le dernier numéro de build majeur.

Tout ce qui est supérieur à cela (> = 17764) sera une génération vNext. lien

Windows Server 2016 sera toujours 10.0.14393. ### où ### incrémente à mesure que les mises à jour cumulatives sont installées.

Windows Server 2019 sera toujours 10.0.17763. ### où ### incrémente à mesure que les mises à jour cumulatives sont installées. lien

Alors BuildNumber 17763 doit toujours correspondre à Windows Server 2019 ou Windows Server, version 1809 (ou Windows 10 1809, mais en vérifiant ProductType vous indique si c'est un serveur).

0
fridoo

La meilleure façon que j'ai trouvée est d'utiliser la méthode GetVersionEx que vous avez mentionnée, si cela retourne 6.2 (ce qui sera le cas pour Windows 8.1 et supérieur), revenez à l'api wmic.
Code ci-dessous extrait de Microsoft pour obtenir le nom du système d'exploitation à l'aide de l'api wmic.
Référence: 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