简体   繁体   中英

WMI Win32_OperatingSystem OSProductSuite gives incorrect value on Windows XP

There is the following C# code that uses WMI to get OsProductSuite value from Win32_OperatingSystem and the analogous wSuiteMask using WinApi function GetVersionEx :

static void Main(string[] args)
{
    try
    {
        var query = new ManagementObjectSearcher("SELECT * FROM Win32_OperatingSystem");

        var name = query.Get()
            .OfType<ManagementObject>()
            .Single()
            .GetPropertyValue("Name");

        Console.WriteLine("Name from WMI = {0}", name);

        var suite = query.Get()
            .OfType<ManagementObject>()
            .Single()
            .GetPropertyValue("OSProductSuite") ?? "<NULL>";

        Console.WriteLine("Suite from WMI = {0}", suite);

        var info = new OsVersionInfo()
        {
            OSVersionInfoSize = Marshal.SizeOf(typeof(OsVersionInfo))
        };
        var gotVersion = GetVersionEx(ref info);

        Console.WriteLine("GetVersionEx gotVersion = {0}", gotVersion);
        Console.WriteLine("GetVersionEx ErrorCode = {0}", Marshal.GetLastWin32Error());

        Console.WriteLine("Suite from GetVersionEx = {0}", info.SuiteMask);
    }
    catch (Exception exc)
    {
        Console.WriteLine(exc);
    }

    Console.WriteLine("Press any key");
    Console.ReadKey();
}

[DllImport("kernel32.dll")]
private static extern bool GetVersionEx(ref OsVersionInfo osVersionInfo);

[StructLayout(LayoutKind.Sequential)]
private struct OsVersionInfo
{
    public int OSVersionInfoSize;
    public int MajorVersion;
    public int MinorVersion;
    public int BuildNumber;
    public int PlatformId;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
    public string szCSDVersion;
    public short ServicePackMajor;
    public short ServicePackMinor;
    public short SuiteMask;
    public byte ProductType;
    public byte Reserved;
}

THE PROBLEM: On all OS after XP both WMI and GetVersionEx report correct OSProductSuite value. But on Windows XP the OSProductSuite from WMI is null.

I originally considered that it is a problem in .NET wrappers for WMI, so I have shamelessly adapted the C++ code from Example: Getting WMI Data from the Local Computer to do the same thing (the changes are in the step 7):

#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 OSProductSuite property
        hr = pclsObj->Get(L"OSProductSuite", 0, &vtProp, 0, 0);

        if (FAILED(hr))
        {
            wcout << L"Failure in WMI";
            return 1;
        }

        wcout << "Variant Type of OSProductSuite from WMI = " << vtProp.vt << endl;
        wcout << "OSProductSuite from WMI = " << vtProp.uintVal << endl;
        VariantClear(&vtProp);

        pclsObj->Release();
    }

    // Cleanup
    // ========

    pSvc->Release();
    pLoc->Release();
    pEnumerator->Release();
    CoUninitialize();

    OSVERSIONINFOEX info;
    info.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);

    auto gotVersion = GetVersionEx((OSVERSIONINFO*)&info);
    if (!gotVersion)
    {
        wcout << L"GetVersionEx error is " << GetLastError();
        return 1;
    }

    wcout << L"wSuiteMask from GetVersionEx = " << info.wSuiteMask;

    wcin.peek();

    return 0;   // Program successfully completed. 
}

But the variant type of the OSProductSuite is VARENUM::VT_NULL (1) , so it seems that the issue is with WMI itself. So, it is some XP issue with WMI, isn't it?

PS: While it is possible that there is some problem with XP distributives I used, or the issue stems from the fact that both machines are virtual (VmWare and SCVMM), it nonetheless seems rather doubtful.

Just as most of the WMI classes Win32_OperatingSystem is declared to have

Minimum supported client Windows Vista

and

Minimum supported server Windows Server 2008

Thus they are officially not guaranteed to work correctly or provide full capabilities on older OS.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM