Reputation: 57
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
Reputation: 57
Finally, I found the root causes:
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.
We must implement GetObjectAsync()
when we use a command like this (Get-WmiObject -Namespace "root\acim" -ClassName "MyHwSetting").MySetHw()
Upvotes: 0