views:

50

answers:

1

The following code fails when ExecMethod is called. Can anyone pinpoint what I am doing wrong?

#define _WIN32_DCOM

#include <iostream>
using namespace std;
#include <comdef.h>
#include <Wbemidl.h>

# pragma comment(lib, "wbemuuid.lib")

int main(int iArgCnt, 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 --------------------------
    // Note: If you are using Windows 2000, you must specify -
    // the default authentication credentials for a user by using
    // a SOLE_AUTHENTICATION_LIST structure in the pAuthList ----
    // parameter of CoInitializeSecurity ------------------------

    hres =  CoInitializeSecurity(
        NULL, 
        -1,                          // COM negotiates service
        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 local root\cimv2 namespace
    // and obtain pointer pSvc to make IWbemServices calls.
    hres = pLoc->ConnectServer(
        _bstr_t(L"ROOT\\wmi"), 
        NULL,
        NULL, 
        0, 
        NULL, 
        0, 
        0, 
        &pSvc
    );

    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 for 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.
    }


    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // set up to call the WmiSetBrightness Method
    BSTR MethodName = SysAllocString(L"WmiSetBrightness");
    BSTR ClassName = SysAllocString(L"WmiMonitorBrightnessMethods");

    IWbemClassObject* pClass = NULL;
    hres = pSvc->GetObject(ClassName, 0, NULL, &pClass, NULL);

    IWbemClassObject* pInParamsDefinition = NULL;
    hres = pClass->GetMethod(MethodName, 0, 
        &pInParamsDefinition, NULL);

    IWbemClassObject* pClassInstance = NULL;
    hres = pInParamsDefinition->SpawnInstance(0, &pClassInstance);

     VARIANT var1;
     VariantInit(&var1);

     V_VT(&var1) = VT_BSTR;
     V_BSTR(&var1) = SysAllocString(L"1000"); 
     hres = pClassInstance->Put(L"Timeout", 0, &var1, CIM_UINT32); //CIM_UINT64

     VARIANT var2;
     VariantInit(&var2);

     V_VT(&var2) = VT_BSTR;
     V_BSTR(&var2) = SysAllocString(L"30"); 
     hres = pClassInstance->Put(L"Brightness", 0, &var2, CIM_UINT8); 



    // Execute Method
    IWbemClassObject* pOutParams = NULL;
    hres = pSvc->ExecMethod(ClassName, MethodName, 0,
    NULL, pClassInstance, &pOutParams, NULL);



    if (FAILED(hres))
    {
        cout << "Could not execute method. Error code = 0x" 
             << hex << hres << endl;
        //VariantClear(&varCommand);
        SysFreeString(ClassName);
        SysFreeString(MethodName);
        pClass->Release();
        pInParamsDefinition->Release();
        pOutParams->Release();
        pSvc->Release();
        pLoc->Release();     
        CoUninitialize();
        return 1;               // Program has failed.
    }

    // To see what the method returned,
    // use the following code.  The return value will
    // be in &varReturnValue
    VARIANT varReturnValue;
    hres = pOutParams->Get(_bstr_t(L"ReturnValue"), 0, 
        &varReturnValue, NULL, 0);


    // Clean up
    //--------------------------
   // VariantClear(&varCommand);
    VariantClear(&varReturnValue);
    SysFreeString(ClassName);
    SysFreeString(MethodName);
    pClass->Release();
    pInParamsDefinition->Release();
    pOutParams->Release();
    pLoc->Release();
    pSvc->Release();
    CoUninitialize();
    return 0;
}
+1  A: 

Since the question was tagged "C++" I tidied up your code by using C++ techniques for failure checking and cleanup. It turned out that you've forgotten to check for failure in several places. The code below reports first failure at GetObject(className, ...).

#define _WIN32_DCOM
#pragma comment(lib, "wbemuuid.lib")

#include <iostream>
#include <string>
#include <stdexcept>
#include <stdlib.h>     // EXIT_FAILURE, EXIT_SUCCESS
using namespace std;

#include <comdef.h>
#include <Wbemidl.h>
#define DEF_SMARTPTR_TYPE( Interface ) \
    _COM_SMARTPTR_TYPEDEF( Interface, __uuidof( Interface ) )

DEF_SMARTPTR_TYPE( IWbemLocator );
DEF_SMARTPTR_TYPE( IWbemServices );
DEF_SMARTPTR_TYPE( IWbemClassObject );

bool throwX( string const& s ) { throw std::runtime_error( s ); }

string hexFrom( unsigned long v )
{
    char    buf[40];
    sprintf( buf, "%08lx", v );
    return buf;
}

struct Fail
{
    string  message;
    explicit Fail( string const& aMessage ): message( aMessage ) {}
};

void operator ||( HRESULT hr, Fail const& failure )
{
    SUCCEEDED( hr )
        || throwX( failure.message + " (Error code 0x" + hexFrom( hr ) + ")" );
}

struct ComLibUsage
{
    struct Threading
    {
        enum Enum {
            singleThreaded  = COINIT_APARTMENTTHREADED,
            multiThreaded   = COINIT_MULTITHREADED
        };
    };

    ComLibUsage( Threading::Enum threading = Threading::multiThreaded )
    {
        ::CoInitializeEx( 0, threading )
            || Fail( "Failed to initialize COM library." );
    }

    ~ComLibUsage() { ::CoUninitialize(); }
};

void cppMain()
{
    // Step 1: --------------------------------------------------
    // Initialize COM. ------------------------------------------
    ComLibUsage     comLibUsage( ComLibUsage::Threading::multiThreaded );

    // Step 2: --------------------------------------------------
    // Set general COM security levels --------------------------
    // Note: If you are using Windows 2000, you must specify -
    // the default authentication credentials for a user by using
    // a SOLE_AUTHENTICATION_LIST structure in the pAuthList ----
    // parameter of CoInitializeSecurity ------------------------
    CoInitializeSecurity(
        NULL, 
        -1,                          // COM negotiates service
        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
        ) || Fail( "Failed to initialize security" );

    // Step 3: ---------------------------------------------------
    // Obtain the initial locator to WMI -------------------------
    IWbemLocatorPtr     pLoc;
    CoCreateInstance(
        CLSID_WbemLocator,             
        0, 
        CLSCTX_INPROC_SERVER, 
        IID_IWbemLocator, (LPVOID *) &pLoc
        ) || Fail( "Failed to create IWbemLocator object." );

    // Step 4: ---------------------------------------------------
    // Connect to WMI through the IWbemLocator::ConnectServer method
    // Connect to the local root\cimv2 namespace
    // and obtain pointer pSvc to make IWbemServices calls.
    IWbemServicesPtr    pSvc;
    pLoc->ConnectServer(
        _bstr_t(L"ROOT\\wmi"), 
        NULL,
        NULL, 
        0, 
        NULL, 
        0, 
        0, 
        &pSvc
        ) || Fail( "Could not connect." );
    cout << "Connected to ROOT\\CIMV2 WMI namespace" << endl;


    // Step 5: --------------------------------------------------
    // Set security levels for the proxy ------------------------
    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 
        ) || Fail( "Could not set proxy blanket" );

    ////////////////////////////////////////////////////////////////
    // set up to call the WmiSetBrightness Method
    _bstr_t     methodName  = L"WmiSetBrightness";
    _bstr_t     className   = L"WmiMonitorBrightnessMethods";

    IWbemClassObjectPtr pClass;
    pSvc->GetObject(className, 0, NULL, &pClass, NULL)
        || Fail( "GetObject(className, ...) failed" );

    IWbemClassObjectPtr pInParamsDefinition;
    pClass->GetMethod(methodName, 0, &pInParamsDefinition, NULL)
        || Fail( "GetMethod(methodName, ...) failed" );

    IWbemClassObjectPtr pClassInstance;
    pInParamsDefinition->SpawnInstance(0, &pClassInstance)
        || Fail( "SpawnInstance failed" );

    _variant_t  var1( L"1000" );
    pClassInstance->Put(L"Timeout", 0, &var1, CIM_UINT32)   //CIM_UINT64
        || Fail( "Put failed for 'Timeout'" );

    _variant_t  var2( L"30" );
    pClassInstance->Put(L"Brightness", 0, &var2, CIM_UINT8)
        || Fail( "Put failed for 'Brightness'" );

    // Execute Method
    IWbemClassObject* pOutParams = NULL;
    //hres = pSvc->ExecMethod(className, methodName, 0,
    //NULL, pClassInstance, &pOutParams, NULL)
        //|| Fail( "Could not execute method" );

    // To see what the method returned,
    // use the following code.  The return value will
    // be in &varReturnValue
    _variant_t varReturnValue;
    pOutParams->Get(_bstr_t(L"ReturnValue"), 0, &varReturnValue, NULL, 0)
        || Fail( "Get failed" );
}

int main()
{
    try
    {
        cppMain();
        return EXIT_SUCCESS;
    }
    catch( exception const& x )
    {
        cerr << "!" << x.what() << endl;
    }
    return EXIT_FAILURE;
}

Cheers & hth. (even if it's a bit on the side of your question!),

Alf P. Steinbach
I ran the code you posted above, I dont get any failure at GetObject(className, ...). It fails for me at pOutParams->Get(_bstr_t(L"ReturnValue"), 0,
aCuria
I uncommented the code and I get a the following printed to stdoutConnected to ROOT\CIMV2 WMI namespace!Could not execute method (Error code 0x8004102f)Press any key to continue . . .
aCuria
@aCuria: huh, if it fails at GetObject then it shouldn't get to the execute method part? Anyway, the HRESULT code is probably an internal one for WMI. If you know about a module that defines those HRESULT values then you can load that module in `errlook` utility and get some explanatory text. But probably all it says is that parameter is wrong or something like that. Possibly the params need to be provided in some other way?
Alf P. Steinbach
It doesnt fail at GetObject for me. I checked out the error code that ExecMethod was returning and I got WBEM_E_INVALID_METHOD_PARAMETERS0x8004102F
aCuria
Alf P. Steinbach
According to this msdn.microsoft.com/en-us/library/aa392103(VS.85).aspx the third param determines if it is a synchronous call.
aCuria