Search code examples
c++exceptionwmiwbem

Unknown Exception from IWbemClassObject::Get


I'm trying to retrieve an "ID" from a WMI object right after persisting it.

After building up the instance, I persist it like so:

hRes = pSvc->PutInstance(pNewInstance, 0, pCtx, &pResult);

All fine and dandy -- it makes it's way into WMI. I then use my pResult, which is IWbemCallResult **ppCallResult to call IWbemCallResult::GetResultObject like so:

IWbemClassObject *ppResultObject = NULL;
hRes = pResult->GetResultObject(WBEM_INFINITE, &ppResultObject);

Great. hRes is S_OK and I appear to have an instance I can retrieve properties on by using IWbemClassObject::Get... so I do:

VARIANT v;
hRes = ppResultObject->Get(L"ID", 0, &v, 0, 0);

No matter the value that actually exists as the "ID", the value in the VARIANT is 0. I can't get the other properties I set on it either (they're also 0). I've tried countless variations of this code flow, using ->Get(CComBSTR("ID")..., ->Get(_bstr_t("ID")..., etc...

hRes is S_OK on this Get too.

If I wrap it all in a try{}catch(...){}, it enters the catch, but I don't know how to determine the exception type or why it would fail. Is there something wrong with this logic or syntax? How can I determine what is going wrong with the Get(L"ID"... call?

This is my 3rd week in C++. Please help me not hate it so much.

Edit: Minimal, Complete, and Verifiable example (as complete and verifiable as it can be without access to my machine and WMI connection):

bool 
myNamespace::myWMIWrapper::createUser(User_t * user)
{
    IWbemLocator * pIWbemLocator = NULL;
    HRESULT hRes = CoCreateInstance(CLSID_WbemLocator,NULL,CLSCTX_ALL,IID_IWbemLocator, (LPVOID *) &pIWbemLocator);

    if (SUCCEEDED(hRes))
    {   
        BSTR combinedUserName = NULL;
        if (m_username != NULL && m_domainname != NULL)
            combinedUserName =_bstr_t(m_domainname) + _bstr_t(_T("\\")) + _bstr_t(m_username);

        hRes = pIWbemLocator->ConnectServer(
                        m_namespace,      // machine name and namespace
                        combinedUserName, // Userid
                        m_password,       // PW
                        NULL,             // Locale
                        0,                // flags
                        NULL,             // Authority
                        pWCtx,            // Context
                        &pWbemServices );
        }

        if (FAILED(hRes))
        {
            LOGGER << _T("Could not connect to the WMI server. Error code = ") << hRes ;
            pIWbemLocator->Release();
            pIWbemLocator = NULL;   
            CoUninitialize();
            return false;
        }

        hRes = NULL;
        IWbemClassObject *pNewClass = NULL;

        BSTR myClassName = SysAllocString(L"My_Class");
        hRes = pWbemServices->GetObject(myClassName, 0, NULL, &pNewClass, NULL);

        if (FAILED(hRes))
        {
            LOGGER << _T("hRes failed. Couldn't find class using GetObject with class name:");
            LOGGER << className;
        }
        SysFreeString(myClassName);

        if (pNewClass == NULL) {
            LOGGER << _T(" No My_Class class Object was found using query.");
            return false;
        }

        LOGGER << _T("Class definition from WMI is found.");
        IWbemClassObject *pNUser = NULL;

        LOGGER << _T(" Creating an instance of My_Class.");
        hRes = S_OK;

        hRes = pNewClass->SpawnInstance(NULL, &pNUser);
        pNewClass->Release();

        if (FAILED(hRes)) {
            LOGGER << _T(" My_Class Object can not be instansiated.");
            return false;
        }

        LOGGER << _T(" Updating properties of My_Class found by WMI query");

        if (user->getFirstName() != NULL) {
            _variant_t v(user->getFirstName()->c_str());
            LOGGER << _T(" Updating property FIRSTNAME->") << V_BSTR(&v) ;
            pNuser->Put(L"FIRSTNAME", 0, &v, 0);
        }

        if (user->getLastName() != NULL) {
        _variant_t v(user->getLastName()->c_str());
        LOGGER <<_T(" Updating property LASTNAME->")<< V_BSTR(&v) ;
        pNuser->Put(L"LASTNAME", 0, &v, 0);
        }

        LOGGER << _T(" Persisting My_Class information");

        IWbemCallResult *pCallRes;
        hRes = pWbemServices->PutInstance(pNuser, WBEM_FLAG_CREATE_OR_UPDATE, NULL, &pCallRes);
        if (FAILED(hRes)) {
          LOGGER << _T(" Persisting of the My_Class object failed.");
          return false;
        }

        _variant_t vnt = NULL;
        IWbemClassObject *objPtr = NULL;
        LOGGER << _T(" calling ->GetResultObject()");
        hRes = pCallRes->GetResultObject(WBEM_INFINITE, &objPtr);

        if (FAILED(hRes)) {
          LOGGER << _T(" calling GetResultObject failed");
          return false;
        }

        LOGGER << _T("Calling ->Get(ID) on instance retrieved from GetResultObject.");
        try {
          // This line gets executed before entering catch(...)
          hRes = objPtr->Get(L"ID", 0, &vnt, NULL, NULL);
        }
        catch (const std::exception& ex) {
          LOGGER << _T(" problem with Get") << ex.what();
        }
        catch (...) { // I'm entering this catch block.
          LOGGER << _T(" unknown exception...............");
        }

        return true;
    }

Solution

  • I resolved the issue by changing

    hRes = pCallRes->GetResultObject(WBEM_INFINITE, &objPtr);
    

    to

    BSTR objPath = NULL;
    hRes = pCallRes->GetResultString(WBEM_INFINITE, &objPath);
    ...
    hRes = pWbemServices->GetObject(objPath, 0, NULL, &objPtr, NULL);
    

    which made vnt in

    hRes = objPtr->Get(L"ID", 0, &vnt, NULL, NULL);
    

    not be 0.

    It appears that there was some processing being done on the instance before it was actually persisted, so the result object that was being retrieved wasn't "ready". When I GetResultString and re-get the object based on that object path, it had the values available in it. Go figure.