CodeLamb
CodeLamb

Reputation: 57

How to develop a C++ decoupled wmi method(not static) provider

I am developing a C++ decoupled WMI provider, but I can only call static methods.

Does anyone know how to call a method from an instance?

PS: the code is based on Windows-classic-samples:

Many thanks :)

Command - static method

PS D:\projects\apps\instance_provider2> Invoke-CimMethod -ClassName MethProvSamp -MethodName Echo -Namespace root/mycim

ReturnValue sOutArg PSComputerName
----------- ------- --------------
          7 default

Method of instance:

PS D:\projects\apps\instance_provider2> (Get-WmiObject -Namespace "root\mycim" -ClassName "HwSetting").SetHw()
Exception calling "SetHw" with "0" argument(s): "Object reference not set to an instance of an object."
At line:1 char:1
+ (Get-WmiObject -Namespace "root\mycim" -ClassName "HwSetting").SetHw()
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : CatchFromBaseAdapterMethodInvoke

Mof

[dynamic: ToInstance, singleton, Provider("DecoupledInstanceProvider2") ]
class HwSetting
{
    [implemented]
    uint32 SetHw();
};

[dynamic: ToInstance, provider("DecoupledInstanceProvider2")]
class MethProvSamp
{
     [implemented, static]
     uint32 Echo([in]string sInArg="default", [out] string sOutArg);
};

Code

/******************************************************************************
 *
 *  Name:   ExecMethodAsync
 *
 *  
 *  Description:
 *
 *          Allow provider to execute a method.
 *
 *****************************************************************************/

HRESULT CProvider_IWbemServices :: ExecMethodAsync ( 

    const BSTR a_ObjectPath ,
    const BSTR a_MethodName ,
    long a_Flags ,
    IWbemContext *a_Context ,
    IWbemClassObject *a_InParams ,
    IWbemObjectSink *a_Sink
) 
{
    HRESULT hr = S_OK;

    printf("%s:%d\n", __FUNCTION__, __LINE__);
    printf("a_ObjectPath:%S\n", a_ObjectPath);
    printf("a_MethodName:%S\n", a_MethodName);

    // Do some minimal error checking.  This code only support the
    // method "Echo" as defined in the mof.  A routine could support
    // more than on method

    if (_wcsicmp(a_MethodName, L"Echo") == 0) {

        IWbemClassObject* pClass = NULL;
        IWbemClassObject* pOutClass = NULL;
        IWbemClassObject* pOutParams = NULL;


        // Impersonate the client: in this simple sample, no protected resources are accessed,
        // but the provider normally needs to perform any operations in the security context 
        // of the client
        hr = CoImpersonateClient();

        if (FAILED(hr))
        {
            a_Sink->SetStatus(0, hr, NULL, NULL);
            return hr;
        }

        //  Check to see if call is at lower than RPC_C_IMP_LEVEL_IMPERSONATE level. If that's the case,
        //  the provider will not be able to impersonate the client to access the protected resources.  

        DWORD t_CurrentImpersonationLevel = GetCurrentImpersonationLevel();
        if (t_CurrentImpersonationLevel < RPC_C_IMP_LEVEL_IMPERSONATE)
        {
            //  Revert before we perform any operations 
            CoRevertToSelf();

            hr = WBEM_E_ACCESS_DENIED;
            a_Sink->SetStatus(0, hr, NULL, NULL);
            return hr;
        }


        // Allocate some BSTRs

        BSTR ClassName = SysAllocString(L"MethProvSamp");
        if (!ClassName)
        {
            CoRevertToSelf();
            a_Sink->SetStatus(0, WBEM_E_OUT_OF_MEMORY, NULL, NULL);
            return hr;
        }

        BSTR InputArgName = SysAllocString(L"sInArg");
        if (!InputArgName)
        {
            SysFreeString(ClassName);
            CoRevertToSelf();
            a_Sink->SetStatus(0, WBEM_E_OUT_OF_MEMORY, NULL, NULL);
            return hr;
        }

        BSTR OutputArgName = SysAllocString(L"sOutArg");
        if (!OutputArgName)
        {
            SysFreeString(ClassName);
            SysFreeString(InputArgName);
            CoRevertToSelf();
            a_Sink->SetStatus(0, WBEM_E_OUT_OF_MEMORY, NULL, NULL);
            return hr;
        }
        BSTR retValName = SysAllocString(L"ReturnValue");
        if (!retValName)
        {
            SysFreeString(ClassName);
            SysFreeString(InputArgName);
            SysFreeString(OutputArgName);
            CoRevertToSelf();
            a_Sink->SetStatus(0, WBEM_E_OUT_OF_MEMORY, NULL, NULL);
            return hr;
        }

        // Get the class object, this is hard coded and matches the class
        // in the MOF.  A more sophisticated example would parse the 
        // ObjectPath to determine the class and possibly the instance.

        hr = m_CoreService->GetObject(ClassName, 0, a_Context, &pClass, NULL);
        if (hr != S_OK)
        {
            a_Sink->SetStatus(0, hr, NULL, NULL);
            return WBEM_S_NO_ERROR;
        }


        // This method returns values, and so create an instance of the
        // output argument class.

        hr = pClass->GetMethod(a_MethodName, 0, NULL, &pOutClass);
        pOutClass->SpawnInstance(0, &pOutParams);

        // Copy the input argument into the output object    

        VARIANT var;
        VariantInit(&var);    // Get the input argument
        a_InParams->Get(InputArgName, 0, &var, NULL, NULL);

        // put it into the output object

        pOutParams->Put(OutputArgName, 0, &var, 0);
        long lLen = (long)wcslen(var.bstrVal);    VariantClear(&var);    var.vt = VT_I4;
        var.lVal = lLen;    // special name for return value.
        pOutParams->Put(retValName, 0, &var, 0);

        // Send the output object back to the client via the sink. Then 
        // release the pointers and free the strings.

        hr = a_Sink->Indicate(1, &pOutParams);
        pOutParams->Release();
        pOutClass->Release();
        pClass->Release();
        SysFreeString(ClassName);
        SysFreeString(InputArgName);
        SysFreeString(OutputArgName);
        SysFreeString(retValName);
    }
    else if (_wcsicmp(a_MethodName, L"SetHw") == 0) {
        printf("SetHw method invoked\n");

        if (m_HwSetting_Object == NULL) {
            printf("m_HwSetting_Object is NULL\n");
            a_Sink->SetStatus(0, WBEM_E_FAILED, NULL, NULL);
            return WBEM_E_FAILED;
        }

        IWbemClassObject* pOutParams = NULL;
        hr = m_HwSetting_Object->GetMethod(a_MethodName, 0, NULL, &pOutParams);
        if (SUCCEEDED(hr)) {
            VARIANT var;
            VariantInit(&var);
            var.vt = VT_I4;
            var.lVal = 0;
            hr = pOutParams->Put(L"ReturnValue", 0, &var, 0);

            if (SUCCEEDED(hr)) {
                hr = a_Sink->Indicate(1, &pOutParams);
            }

            pOutParams->Release();
        }
        else {
            printf("Failed to get method: %S\n", a_MethodName);
        }
    } else {
        return WBEM_E_INVALID_PARAMETER;
    }

    // all done now, set the status
    hr = a_Sink->SetStatus(0, WBEM_S_NO_ERROR, NULL, NULL);
    return WBEM_S_NO_ERROR;
}


HRESULT CProvider_IWbemServices :: CreateInstanceEnumAsync (

    const BSTR a_Class ,
    long a_Flags ,
    IWbemContext *a_Context ,
    IWbemObjectSink *a_Sink
) 
{
    printf("%s:%d %S\n", __FUNCTION__, __LINE__, a_Class);
    //Impersonate the client
    HRESULT hr = S_OK ;

    if ( _wcsicmp ( a_Class , L"ContactInfo" ) == 0 ) 
    {
        //Grant access for built-in admins, local system, local admins, local service and network service.
        PSECURITY_DESCRIPTOR secDescriptor = NULL;
        BOOL bRes = ConvertStringSecurityDescriptorToSecurityDescriptor //this function is only available on Windows 2000 and above
            ( L"O:BAG:BAD:(A;;0x10000001;;;BA)(A;;0x10000001;;;SY)(A;;0x10000001;;;LA)(A;;0x10000001;;;SY)(A;;0x10000001;;;S-1-5-20)(A;;0x10000001;;;S-1-5-19)",
            SDDL_REVISION_1,
            (PSECURITY_DESCRIPTOR *) &secDescriptor,
            NULL);

        if (! bRes)
        {
            hr = WBEM_E_ACCESS_DENIED;
            a_Sink->SetStatus ( 0 , hr , NULL , NULL ) ;
            return hr ;
        }

        hr = CoImpersonateClient () ;
        if ( FAILED ( hr ) )
        {
            LocalFree(secDescriptor);

            a_Sink->SetStatus ( 0 , hr , NULL , NULL ) ;
            return hr ;
        }   


        // perform an access check. 
        
        hr = CheckAccess((SECURITY_DESCRIPTOR *)secDescriptor, 
                            MASK_CLIENT_ACCESS_BIND,
                            &s_ClientAccessMapping);

        LocalFree(secDescriptor);

        //  Revert before we perform any operations 
        CoRevertToSelf () ;

        if (FAILED(hr))
        {
            hr = WBEM_E_ACCESS_DENIED;
            a_Sink->SetStatus ( 0 , hr , NULL , NULL ) ;
            return hr ;
        }       
        

        //Enumerate the instances.
        hr = CreateInstanceEnumAsync_Contacts ( 

            m_ContactInfo_Object ,
            a_Flags ,
            a_Context , 
            a_Sink
        ) ;

    }
    else if (_wcsicmp(a_Class, L"HwSetting") == 0)
    {
        IWbemClassObject* pClassObject = NULL;
        hr = m_CoreService->GetObject(a_Class, 0, a_Context, &pClassObject, NULL);
        if (SUCCEEDED(hr))
        {
            hr = CreateInstanceEnumAsync_HwSetting(pClassObject, a_Flags, a_Context, a_Sink);
            pClassObject->Release();
        }
    }
    else
    {
        hr = WBEM_E_INVALID_CLASS ;
    }

/*
 *  Inform WMI of status of call.
 */


    a_Sink->SetStatus ( 0 , hr , NULL , NULL ) ;

    return hr ;
}

Upvotes: 1

Views: 34

Answers (1)

CodeLamb
CodeLamb

Reputation: 57

Finally, I found the root causes:

  1. I use the command Get-WmiObject -Namespace "root\acim" -ClassName "HwSetting" | Get-Member to find that the registered method is SetHw(System.String name, System.String value), but it doesn't match my setting of SetHw() which does not have any arguments. So I re-compiled mof by mofcomp.exe.

  2. We must implement GetObjectAsync() when we use a command like this (Get-WmiObject -Namespace "root\acim" -ClassName "MyHwSetting").MySetHw()

Upvotes: 0

Related Questions