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:
Windows Server 2019:
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.
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);
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).
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.
}