mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1803 lines
47 KiB
1803 lines
47 KiB
//***************************************************************************
|
|
//
|
|
// Copyright (c) 1998-2000 Microsoft Corporation.
|
|
//
|
|
// File: cwbemdsp.cpp
|
|
//
|
|
// Description :
|
|
// Implementation of the IDispatch interface for Wbem Objects.
|
|
// This is mostly standard, except for the additional support for
|
|
// specifying the name of a Wbem class property/method directly as if it
|
|
// was a property/method of the actual CWbemObject class ("dot notation")
|
|
//
|
|
// Part of : WBEM automation interface layer
|
|
//
|
|
// History:
|
|
// corinaf 4/3/98 Created
|
|
//
|
|
//***************************************************************************
|
|
|
|
#include "precomp.h"
|
|
|
|
const unsigned long CWbemDispID::s_wmiDispIdTypeMask = 0x03000000;
|
|
const unsigned long CWbemDispID::s_wmiDispIdTypeStatic = 0x00000000;
|
|
const unsigned long CWbemDispID::s_wmiDispIdTypeSchema = 0x01000000;
|
|
const unsigned long CWbemDispID::s_wmiDispIdSchemaTypeMask = 0x00800000;
|
|
const unsigned long CWbemDispID::s_wmiDispIdSchemaTypeProperty = 0x00800000;
|
|
const unsigned long CWbemDispID::s_wmiDispIdSchemaTypeMethod = 0x00000000;
|
|
const unsigned long CWbemDispID::s_wmiDispIdSchemaElementIDMask = 0x007FFFFF;
|
|
|
|
//Forward declaration
|
|
|
|
HRESULT assignArrayElementToVariant(SAFEARRAY *psa, VARTYPE vt, long inx, VARIANT *pvResult);
|
|
void assignVariantToArrayElement(SAFEARRAY *psa, VARTYPE vt, long inx, VARIANT *pvNewVal);
|
|
VARTYPE CimTypeToVtType(CIMTYPE lType);
|
|
HRESULT VariantChangeByValToByRef(VARIANT *dest, VARIANT *source, VARTYPE destType);
|
|
|
|
class CWbemSchemaIDCache
|
|
{
|
|
private:
|
|
typedef map<CComBSTR, CWbemDispID, BSTRless> DispIDNameMap;
|
|
|
|
unsigned long m_nextId;
|
|
DispIDNameMap m_cache;
|
|
CWbemDispatchMgr *m_pDispatchMgr;
|
|
|
|
bool FindPropertyName (BSTR bsName);
|
|
bool GetMethod (BSTR bstrMethodName, SAFEARRAY **ppsaInParams, SAFEARRAY **ppsaOutParams,
|
|
CComPtr<IWbemClassObject> & pInParams, CComPtr<IWbemClassObject> & pOutParams);
|
|
bool GetIdOfMethodParameter(BSTR bstrParamName, CComPtr<IWbemClassObject> & pParams, long *pId);
|
|
|
|
static bool FindMemberInArray(BSTR bstrName, SAFEARRAY *psaNames);
|
|
|
|
public:
|
|
CWbemSchemaIDCache (CWbemDispatchMgr *pDispMgr) :
|
|
m_nextId (0),
|
|
m_pDispatchMgr (pDispMgr) {}
|
|
virtual ~CWbemSchemaIDCache ();
|
|
|
|
HRESULT GetDispID (LPWSTR FAR* rgszNames, unsigned int cNames, DISPID FAR* rgdispid);
|
|
bool GetName (DISPID dispId, CComBSTR & bsName);
|
|
};
|
|
|
|
|
|
CWbemDispatchMgr::CWbemDispatchMgr(CSWbemServices *pWbemServices,
|
|
CSWbemObject *pSWbemObject) :
|
|
m_pWbemServices (pWbemServices),
|
|
m_pSWbemObject (pSWbemObject), // Backpointer to parent (not AddRef'd)
|
|
m_pWbemClass (NULL),
|
|
m_pTypeInfo (NULL),
|
|
m_pCTypeInfo (NULL),
|
|
m_hResult (S_OK)
|
|
{
|
|
m_pSchemaCache = new CWbemSchemaIDCache (this);
|
|
|
|
if (m_pWbemServices)
|
|
m_pWbemServices->AddRef ();
|
|
|
|
m_pWbemObject = pSWbemObject->GetIWbemClassObject ();
|
|
}
|
|
|
|
CWbemDispatchMgr::~CWbemDispatchMgr()
|
|
{
|
|
RELEASEANDNULL(m_pWbemServices)
|
|
RELEASEANDNULL(m_pWbemObject)
|
|
RELEASEANDNULL(m_pWbemClass)
|
|
RELEASEANDNULL(m_pTypeInfo)
|
|
RELEASEANDNULL(m_pCTypeInfo)
|
|
DELETEANDNULL(m_pSchemaCache)
|
|
}
|
|
|
|
void CWbemDispatchMgr::SetNewObject (IWbemClassObject *pNewObject)
|
|
{
|
|
if (m_pWbemObject && pNewObject)
|
|
{
|
|
m_pWbemObject->Release ();
|
|
m_pWbemObject = pNewObject;
|
|
m_pWbemObject->AddRef ();
|
|
|
|
CComVariant var;
|
|
|
|
if (SUCCEEDED(pNewObject->Get (WBEMS_SP_GENUS, 0, &var, NULL, NULL)) &&
|
|
(WBEM_GENUS_CLASS == var.lVal))
|
|
{
|
|
// This is a class, so update the class object too
|
|
if (m_pWbemClass)
|
|
m_pWbemClass->Release ();
|
|
|
|
m_pWbemClass = pNewObject;
|
|
m_pWbemClass->AddRef ();
|
|
}
|
|
|
|
// Clear out the caches
|
|
if (m_pSchemaCache)
|
|
{
|
|
delete m_pSchemaCache;
|
|
m_pSchemaCache = new CWbemSchemaIDCache (this);
|
|
}
|
|
}
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CWbemDispatchMgr::GetTypeInfoCount(unsigned int FAR* pctinfo)
|
|
{
|
|
*pctinfo = 1;
|
|
return NOERROR;
|
|
}
|
|
|
|
|
|
STDMETHODIMP CWbemDispatchMgr::GetTypeInfo(unsigned int itinfo,
|
|
LCID lcid,
|
|
ITypeInfo FAR* FAR* pptinfo)
|
|
{
|
|
HRESULT hr;
|
|
ITypeLib *pTypeLib = NULL;
|
|
|
|
//If Type Info is not cached already - load the library and
|
|
//get the Type Info, then cache it for further access
|
|
if (!m_pTypeInfo)
|
|
{
|
|
|
|
// Load Type Library.
|
|
hr = LoadRegTypeLib(LIBID_WbemScripting, 1, 0, lcid, &pTypeLib);
|
|
if (FAILED(hr))
|
|
{
|
|
// if it wasn't registered, try to load it from the path
|
|
// if this succeeds, it will have registered the type library for us
|
|
// for the next time.
|
|
hr = LoadTypeLib(OLESTR("wbemdisp.tlb"), &pTypeLib);
|
|
if(FAILED(hr))
|
|
return hr;
|
|
}
|
|
|
|
// Get type information for interface of the object.
|
|
hr = pTypeLib->GetTypeInfoOfGuid(IID_ISWbemObjectEx, &m_pTypeInfo);
|
|
pTypeLib->Release();
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
}
|
|
|
|
//AddRef whenever returning another pointer to this
|
|
m_pTypeInfo->AddRef();
|
|
*pptinfo = m_pTypeInfo;
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
STDMETHODIMP CWbemDispatchMgr::GetClassInfo(ITypeInfo FAR* FAR* pptinfo)
|
|
{
|
|
HRESULT hr;
|
|
ITypeLib *pTypeLib = NULL;
|
|
|
|
//If Type Info is not cached already - load the library and
|
|
//get the Type Info, then cache it for further access
|
|
if (!m_pCTypeInfo)
|
|
{
|
|
|
|
// Load Type Library.
|
|
hr = LoadRegTypeLib(LIBID_WbemScripting, 1, 0, 0, &pTypeLib);
|
|
if (FAILED(hr))
|
|
{
|
|
// if it wasn't registered, try to load it from the path
|
|
// if this succeeds, it will have registered the type library for us
|
|
// for the next time.
|
|
hr = LoadTypeLib(OLESTR("wbemdisp.tlb"), &pTypeLib);
|
|
if(FAILED(hr))
|
|
return hr;
|
|
}
|
|
|
|
// Get type information for coclass of the object.
|
|
hr = pTypeLib->GetTypeInfoOfGuid(CLSID_SWbemObjectEx, &m_pCTypeInfo);
|
|
pTypeLib->Release();
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
}
|
|
|
|
//AddRef whenever returning another pointer to this
|
|
m_pCTypeInfo->AddRef();
|
|
*pptinfo = m_pCTypeInfo;
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CWbemDispatchMgr::GetIDsOfNames(REFIID iid, //always IID_NULL
|
|
LPWSTR FAR* rgszNames,
|
|
unsigned int cNames,
|
|
LCID lcid,
|
|
DISPID FAR* rgdispid)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
CComPtr<ITypeInfo> pITypeInfo;
|
|
|
|
if (SUCCEEDED(hr = GetTypeInfo(0, lcid, &pITypeInfo)))
|
|
{
|
|
// See if this is a static property or method
|
|
if (FAILED(hr = DispGetIDsOfNames(pITypeInfo,
|
|
rgszNames,
|
|
cNames,
|
|
rgdispid)))
|
|
{
|
|
// Not static - try schema
|
|
if (m_pSchemaCache && FAILED(hr = m_pSchemaCache->GetDispID (rgszNames, cNames, rgdispid)))
|
|
{
|
|
rgdispid[0] = DISPID_UNKNOWN;
|
|
hr = DISP_E_UNKNOWNNAME;
|
|
}
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
|
|
STDMETHODIMP CWbemDispatchMgr::Invoke(DISPID dispidMember,
|
|
REFIID iid, LCID lcid,
|
|
unsigned short wFlags,
|
|
DISPPARAMS FAR* pdispparams,
|
|
VARIANT FAR* pvarResult,
|
|
EXCEPINFO FAR* pexcepinfo,
|
|
unsigned int FAR* puArgErr)
|
|
{
|
|
HRESULT hr;
|
|
ITypeInfo *pTypeInfo = NULL;
|
|
|
|
//Get the type info
|
|
hr = GetTypeInfo(0, lcid, &pTypeInfo);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
m_hResult = S_OK;
|
|
|
|
CWbemDispID dispId (dispidMember);
|
|
|
|
// Is this a regular dispId
|
|
if (dispId.IsStatic ())
|
|
{
|
|
// Check for inbound NULLs masquerading as defaulted parameters
|
|
if (wFlags & DISPATCH_METHOD)
|
|
MapNulls (pdispparams);
|
|
|
|
hr = DispInvoke((IDispatch *) ((ISWbemObjectEx *)m_pSWbemObject),
|
|
pTypeInfo,
|
|
dispidMember,
|
|
wFlags,
|
|
pdispparams,
|
|
pvarResult,
|
|
pexcepinfo,
|
|
puArgErr
|
|
);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
// Try the error handler for this object in case it can handle this
|
|
hr = HandleError (dispidMember, wFlags, pdispparams, pvarResult, puArgErr, hr);
|
|
}
|
|
}
|
|
else if (dispId.IsSchema ())
|
|
{
|
|
//Otherwise - this is a WBEM property or method, so we implement
|
|
//the invocation ourselves...
|
|
|
|
ResetLastErrors ();
|
|
|
|
if (dispId.IsSchemaMethod ()) //WBEM method
|
|
hr = InvokeWbemMethod(dispidMember,
|
|
pdispparams,
|
|
pvarResult);
|
|
else if (dispId.IsSchemaProperty ()) //WBEM property
|
|
hr = InvokeWbemProperty(dispidMember,
|
|
wFlags,
|
|
pdispparams,
|
|
pvarResult,
|
|
pexcepinfo,
|
|
puArgErr);
|
|
else
|
|
hr = DISP_E_MEMBERNOTFOUND;
|
|
|
|
if (FAILED(hr))
|
|
RaiseException (hr);
|
|
}
|
|
|
|
if (FAILED (m_hResult))
|
|
{
|
|
if (NULL != pexcepinfo)
|
|
SetException (pexcepinfo, m_hResult, L"SWbemObjectEx");
|
|
|
|
hr = DISP_E_EXCEPTION;
|
|
}
|
|
|
|
if (pTypeInfo)
|
|
pTypeInfo->Release();
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
CWbemDispatchMgr::InvokeWbemProperty(DISPID dispid,
|
|
unsigned short wFlags,
|
|
DISPPARAMS FAR* pdispparams,
|
|
VARIANT FAR* pvarResult,
|
|
EXCEPINFO FAR* pexcepinfo,
|
|
unsigned int FAR* puArgErr)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
|
|
if (m_pSchemaCache)
|
|
{
|
|
BOOL bIsGetOperation = (DISPATCH_PROPERTYGET & wFlags);
|
|
|
|
if (bIsGetOperation)
|
|
{
|
|
//Check that the output parameter is valid
|
|
if (pvarResult == NULL)
|
|
return E_INVALIDARG;
|
|
}
|
|
else
|
|
{
|
|
//Check input parameters
|
|
if ((pdispparams->cArgs < 1) || (pdispparams->cArgs > 2))
|
|
return DISP_E_BADPARAMCOUNT;
|
|
|
|
if ((pdispparams->cNamedArgs != 1) ||
|
|
(pdispparams->cNamedArgs == 1 &&
|
|
pdispparams->rgdispidNamedArgs[0] != DISPID_PROPERTYPUT))
|
|
return DISP_E_PARAMNOTOPTIONAL;
|
|
}
|
|
|
|
//For both get & put, we need to first get the property
|
|
// (for put we need to validate the syntax)
|
|
CComBSTR bsPropertyName;
|
|
|
|
if (m_pSchemaCache->GetName (dispid, bsPropertyName))
|
|
{
|
|
SAFEARRAY *psaNames = NULL;
|
|
long inx;
|
|
VARIANT vPropVal;
|
|
long lArrayPropInx;
|
|
CIMTYPE lPropType;
|
|
|
|
//Get the value of this property
|
|
//-------------------------------------
|
|
VariantInit(&vPropVal);
|
|
if (FAILED (hr = m_pWbemObject->Get(bsPropertyName, 0, &vPropVal, &lPropType, NULL)))
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
// The expected VT type for the proposed property value
|
|
VARTYPE expectedVarType = CimTypeToVtType (lPropType & ~CIM_FLAG_ARRAY);
|
|
|
|
//If we are in a get operation
|
|
//----------------------------------
|
|
if (bIsGetOperation)
|
|
{
|
|
//If the property is an embedded object, we might need to convert it from
|
|
//a VT_UNKNOWN to a VT_DISPATCH
|
|
if (SUCCEEDED(hr = MapFromCIMOMObject(m_pWbemServices, &vPropVal,
|
|
m_pSWbemObject, bsPropertyName)))
|
|
{
|
|
//If the property is an array, need to check for index and get that element
|
|
if ((lPropType & CIM_FLAG_ARRAY) && (pdispparams->cArgs > 0))
|
|
{
|
|
//Note: currently we support single dimension arrays only, so we only
|
|
// look for one index
|
|
VARIANT indexVar;
|
|
VariantInit (&indexVar);
|
|
// Attempt to coerce the index argument into a value suitable for an array index
|
|
if (S_OK == VariantChangeType (&indexVar, &pdispparams->rgvarg[0], 0, VT_I4))
|
|
{
|
|
lArrayPropInx = V_I4(&indexVar);
|
|
|
|
//Fill in the result variant with the requested array element
|
|
hr = assignArrayElementToVariant(vPropVal.parray, (V_VT(&vPropVal) & ~VT_ARRAY),
|
|
lArrayPropInx, pvarResult);
|
|
}
|
|
else
|
|
hr = DISP_E_TYPEMISMATCH;
|
|
|
|
VariantClear (&indexVar);
|
|
}
|
|
else //If it's not an array index - copy to output param and we're done
|
|
{
|
|
// Check if it's an array value and convert as necessary
|
|
if (V_ISARRAY(&vPropVal))
|
|
hr = ConvertArrayRev(pvarResult, &vPropVal);
|
|
else
|
|
hr = VariantCopy (pvarResult, &vPropVal);
|
|
}
|
|
}
|
|
} //Property Get
|
|
|
|
//Otherwise (put operation)
|
|
//---------------------------------
|
|
else
|
|
{
|
|
/*
|
|
* Need to translate this into a call to SWbemProperty.put_Value: easiest way
|
|
* to do this is to
|
|
* (A) get the SWbemProperty object for this property
|
|
* (B) Call IDispatch::Invoke on that object, passing in the value
|
|
* This way we get the error handling behavior too.
|
|
*/
|
|
|
|
CComPtr<ISWbemPropertySet> pISWbemPropertySet;
|
|
|
|
if (SUCCEEDED(hr = m_pSWbemObject->get_Properties_ (&pISWbemPropertySet)))
|
|
{
|
|
CComPtr<ISWbemProperty> pISWbemProperty;
|
|
|
|
if (SUCCEEDED(hr = pISWbemPropertySet->Item (bsPropertyName, 0, &pISWbemProperty)))
|
|
{
|
|
// NB: The Value property of ISWbemProperty is the "default" automation property
|
|
hr = pISWbemProperty->Invoke (
|
|
DISPID_VALUE,
|
|
IID_NULL,
|
|
0,
|
|
wFlags,
|
|
pdispparams,
|
|
pvarResult,
|
|
pexcepinfo,
|
|
puArgErr);
|
|
|
|
// Use our more specific error here if we have one
|
|
if (FAILED(hr) && pexcepinfo)
|
|
hr = pexcepinfo->scode;
|
|
}
|
|
}
|
|
|
|
} //Property Put
|
|
|
|
VariantClear(&vPropVal);
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// SCODE CWbemDispatchMgr::InvokeWbemMethod
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Invoke the method via direct access.
|
|
//
|
|
// PARAMETERS:
|
|
//
|
|
// dispid The dispid od the method
|
|
// pdispparams Pointer to DISPPARAMS for this invocation
|
|
// pvarResult On successful return holds return value (if any)
|
|
//
|
|
// RETURN VALUES:
|
|
//
|
|
//***************************************************************************
|
|
|
|
HRESULT CWbemDispatchMgr::InvokeWbemMethod(
|
|
DISPID dispid,
|
|
DISPPARAMS FAR* pdispparams,
|
|
VARIANT FAR* pvarResult
|
|
)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
|
|
if (m_pWbemServices && m_pSchemaCache)
|
|
{
|
|
//Currently we don't support named arguments
|
|
if (pdispparams->cNamedArgs > 0)
|
|
return DISP_E_NONAMEDARGS;
|
|
|
|
//Map the dispid to a method name
|
|
CComBSTR bsMethodName;
|
|
|
|
if (m_pSchemaCache->GetName (dispid, bsMethodName))
|
|
{
|
|
// Build up the inparameters (if any)
|
|
CComPtr<IWbemClassObject> pInParameters;
|
|
CComPtr<IWbemClassObject> pOutParameters;
|
|
|
|
//Get the input parameters object of the method (may be NULL)
|
|
if (SUCCEEDED (hr = m_pWbemClass->GetMethod(bsMethodName, 0, &pInParameters,
|
|
&pOutParameters)))
|
|
{
|
|
CComPtr<IWbemClassObject> pInParamsInstance;
|
|
|
|
if (pInParameters)
|
|
hr = MapInParameters (pdispparams, pInParameters, &pInParamsInstance);
|
|
|
|
if (SUCCEEDED (hr))
|
|
{
|
|
CComPtr<IWbemServices> pService = m_pWbemServices->GetIWbemServices ();
|
|
|
|
if (pService)
|
|
{
|
|
// Need the RELPATH to specify the target class or instance
|
|
VARIANT vObjectPathVal;
|
|
VariantInit(&vObjectPathVal);
|
|
|
|
if (SUCCEEDED (hr = m_pWbemObject->Get
|
|
(WBEMS_SP_RELPATH, 0, &vObjectPathVal, NULL, NULL)))
|
|
{
|
|
/*
|
|
* If a "keyless" object slips through the net its __RELPATH
|
|
* value will be VT_NULL. At this point we should fail gracefully.
|
|
*/
|
|
if (VT_BSTR == V_VT(&vObjectPathVal))
|
|
{
|
|
// Execute the CIMOM method
|
|
CComPtr<IWbemClassObject> pOutParamsInstance;
|
|
|
|
bool needToResetSecurity = false;
|
|
HANDLE hThreadToken = NULL;
|
|
CSWbemSecurity *pSecurityInfo = m_pWbemServices->GetSecurityInfo ();
|
|
|
|
if (pSecurityInfo && pSecurityInfo->SetSecurity (needToResetSecurity, hThreadToken))
|
|
{
|
|
|
|
if (SUCCEEDED(hr = pService->ExecMethod(V_BSTR(&vObjectPathVal),
|
|
bsMethodName, 0, NULL,
|
|
pInParamsInstance, &pOutParamsInstance, NULL)))
|
|
hr = MapOutParameters (pdispparams, pOutParameters,
|
|
pOutParamsInstance, pvarResult);
|
|
|
|
SetWbemError (m_pWbemServices);
|
|
}
|
|
|
|
if (pSecurityInfo)
|
|
{
|
|
// Restore original privileges on this thread
|
|
if (needToResetSecurity)
|
|
pSecurityInfo->ResetSecurity (hThreadToken);
|
|
|
|
pSecurityInfo->Release ();
|
|
}
|
|
}
|
|
else
|
|
hr = WBEM_E_FAILED;
|
|
}
|
|
|
|
VariantClear (&vObjectPathVal);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// SCODE CWbemDispatchMgr::MapOutParameters
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Invoke the method via direct access.
|
|
//
|
|
// PARAMETERS:
|
|
//
|
|
// dispparams Pointer to DISPPARAMS for this invocation
|
|
// pOutParameters Class template for out parameters
|
|
// pOutParamsInstance Addresses the IWbemClassObject to hold the
|
|
// out parameters (if any) - may be NULL
|
|
// pvarResult On successful return holds return value (if any)
|
|
//
|
|
// RETURN VALUES:
|
|
//
|
|
//***************************************************************************
|
|
|
|
HRESULT CWbemDispatchMgr::MapOutParameters (
|
|
DISPPARAMS FAR* pdispparams,
|
|
IWbemClassObject *pOutParameters,
|
|
IWbemClassObject *pOutParamsInstance,
|
|
VARIANT FAR* pvarResult
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
//For each "out" parameter in the output parameters object (if there is one),
|
|
//find it's id, then look for the parameter with this id in the arguments array
|
|
//and set the return parameter value accordingly
|
|
//----------------------------------------------------------------------------
|
|
|
|
if (pOutParameters && pOutParamsInstance)
|
|
{
|
|
//Start an enumeration through the "out" parameters class template
|
|
if (SUCCEEDED (hr = pOutParameters->BeginEnumeration(WBEM_FLAG_NONSYSTEM_ONLY)))
|
|
{
|
|
BSTR bstrId = SysAllocString(L"id");
|
|
BSTR bstrParamName = NULL;
|
|
|
|
/*
|
|
* For each property in the outparams class template, get the [id]
|
|
* to map the relevant posistional value in the pdispparams.
|
|
*/
|
|
while (WBEM_S_NO_ERROR ==
|
|
(hr != pOutParameters->Next(0, &bstrParamName, NULL, NULL, NULL)))
|
|
{
|
|
// Get the returned parameter value from the instance
|
|
VARIANT vParamVal;
|
|
VariantInit(&vParamVal);
|
|
|
|
if (SUCCEEDED (pOutParamsInstance->Get (bstrParamName, 0, &vParamVal, NULL, NULL)))
|
|
{
|
|
//If this is the return value, set it separately
|
|
if (!_wcsicmp(bstrParamName, L"ReturnValue"))
|
|
{
|
|
if (pvarResult)
|
|
hr = MapReturnValue (pvarResult, &vParamVal);
|
|
}
|
|
//Otherwise - regular out parameter
|
|
else
|
|
{
|
|
IWbemQualifierSet *pQualSet = NULL;
|
|
|
|
//Get the id of this parameter (it's the "id" qualifier)
|
|
if (SUCCEEDED (hr = pOutParameters->GetPropertyQualifierSet
|
|
(bstrParamName, &pQualSet)))
|
|
{
|
|
VARIANT vIdVal;
|
|
VariantInit(&vIdVal);
|
|
|
|
if (SUCCEEDED (hr = pQualSet->Get(bstrId, 0, &vIdVal, NULL)))
|
|
{
|
|
//Calculate the position of this id in the arguments array
|
|
long pos = (pdispparams->cArgs - 1) - V_I4(&vIdVal);
|
|
|
|
// If its out of range, too bad
|
|
if ((0 <= pos) && (pos < (long) pdispparams->cArgs))
|
|
hr = MapOutParameter (&pdispparams->rgvarg[pos], &vParamVal);
|
|
}
|
|
|
|
VariantClear(&vIdVal);
|
|
pQualSet->Release();
|
|
}
|
|
}
|
|
}
|
|
|
|
VariantClear (&vParamVal);
|
|
SysFreeString (bstrParamName);
|
|
bstrParamName = NULL;
|
|
} //while
|
|
|
|
SysFreeString (bstrId);
|
|
}
|
|
} //if pOutParameters
|
|
|
|
return hr;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// SCODE CWbemDispatchMgr::MapReturnValue
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Map the method return value
|
|
//
|
|
// PARAMETERS:
|
|
//
|
|
// pDest On successful return holds return value (if any)
|
|
// pSrc The variant value to map
|
|
//
|
|
//
|
|
// RETURN VALUES:
|
|
//
|
|
//***************************************************************************
|
|
|
|
HRESULT CWbemDispatchMgr::MapReturnValue (
|
|
VARIANT FAR* pDest,
|
|
VARIANT FAR* pSrc
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
//If the return value is a VT_UNKNOWN, we need to wrap into a
|
|
//VT_DISPATCH before passing it back
|
|
if (SUCCEEDED (hr = MapFromCIMOMObject(m_pWbemServices, pSrc)))
|
|
{
|
|
// Handle arrays correctly (must always be VT_ARRAY|VT_VARIANT)
|
|
if(V_VT(pSrc) & VT_ARRAY)
|
|
hr = ConvertArrayRev(pDest, pSrc);
|
|
else
|
|
hr = VariantCopy (pDest, pSrc);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// SCODE CWbemDispatchMgr::MapOutParameter
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Map a (possibly by reference) out parameter
|
|
//
|
|
// PARAMETERS:
|
|
//
|
|
// pDest On successful return holds return value (if any)
|
|
// pVal The variant value to map
|
|
//
|
|
//
|
|
// RETURN VALUES:
|
|
//
|
|
//***************************************************************************
|
|
|
|
HRESULT CWbemDispatchMgr::MapOutParameter (
|
|
VARIANT FAR* pDest,
|
|
VARIANT FAR* pSrc
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
//If the return value is a VT_UNKNOWN, we need to wrap into a
|
|
//VT_DISPATCH before passing it back
|
|
if (SUCCEEDED (hr = MapFromCIMOMObject(m_pWbemServices, pSrc)))
|
|
{
|
|
VARIANT tempVal;
|
|
VariantInit (&tempVal);
|
|
|
|
// Handle arrays correctly (must always be VT_ARRAY|VT_VARIANT)
|
|
if(V_VT(pSrc) & VT_ARRAY)
|
|
hr = ConvertArrayRev(&tempVal, pSrc);
|
|
else
|
|
hr = VariantCopy (&tempVal, pSrc);
|
|
|
|
// Finally take care of ensuring we produce BYREFs if necessary
|
|
if (SUCCEEDED (hr))
|
|
hr = VariantChangeByValToByRef(pDest, &tempVal, V_VT(pDest));
|
|
|
|
VariantClear (&tempVal);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//***************************************************************************
|
|
//
|
|
// SCODE CWbemDispatchMgr::MapInParameters
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Map the in parameters to a method
|
|
//
|
|
// PARAMETERS:
|
|
//
|
|
// pdispparams DISPPARAMS containing the in parameters
|
|
// pInParameters Class template for method input parameters
|
|
// ppInParamsInstance On successful return holds the mapped parameters
|
|
//
|
|
// RETURN VALUES:
|
|
//
|
|
//***************************************************************************
|
|
|
|
HRESULT CWbemDispatchMgr::MapInParameters (
|
|
DISPPARAMS FAR* pdispparams,
|
|
IWbemClassObject *pInParameters,
|
|
IWbemClassObject **ppInParamsInstance
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
*ppInParamsInstance = NULL;
|
|
|
|
//Spawn an instance to fill in with values
|
|
if (SUCCEEDED (hr = pInParameters->SpawnInstance(0, ppInParamsInstance)))
|
|
{
|
|
/*
|
|
* Iterate through the "in" parameters object properties in the class to find the
|
|
* ID positional qualifier. Note we do this in the InParams class rather than
|
|
* the spawned instance to protect ourselves against the case where the [id]
|
|
* qualifier has been declared without the "propagate to instance" flavor setting,
|
|
*/
|
|
if (SUCCEEDED (hr = pInParameters->BeginEnumeration(WBEM_FLAG_NONSYSTEM_ONLY)))
|
|
{
|
|
BSTR bstrParamName = NULL;
|
|
BSTR bstrId = SysAllocString(L"id");
|
|
CIMTYPE lType;
|
|
|
|
//For each property in the inparams object
|
|
while (WBEM_S_NO_ERROR ==
|
|
(hr = pInParameters->Next(0, &bstrParamName, NULL, &lType, NULL)))
|
|
{
|
|
IWbemQualifierSet *pQualSet = NULL;
|
|
|
|
//Get the id of this parameter (it's the "id" qualifier)
|
|
if (SUCCEEDED(hr =
|
|
pInParameters->GetPropertyQualifierSet(bstrParamName, &pQualSet)))
|
|
{
|
|
VARIANT vIdVal;
|
|
VariantInit(&vIdVal);
|
|
|
|
if (SUCCEEDED(hr = pQualSet->Get(bstrId, 0, &vIdVal, NULL)))
|
|
{
|
|
//Calculate the position of this id in the arguments array
|
|
long pos = (pdispparams->cArgs - 1) - V_I4(&vIdVal);
|
|
|
|
// If no argument specified, we won't set it in ppInParamsInstance
|
|
// and just assume it will be defaulted
|
|
if ((0 <= pos) && (pos < (long) pdispparams->cArgs))
|
|
{
|
|
VARIANT vParamVal;
|
|
VariantInit (&vParamVal);
|
|
|
|
if (SUCCEEDED (hr = MapInParameter
|
|
(&vParamVal, &pdispparams->rgvarg[pos], lType)))
|
|
{
|
|
// If we have a VT_ERROR with DISP_E_PARAMNOTFOUND this
|
|
// is a "missing" parameter - we just fail to set it and
|
|
// let it default in the instance
|
|
|
|
if ((VT_ERROR == V_VT(&vParamVal)) && (DISP_E_PARAMNOTFOUND == vParamVal.scode))
|
|
{
|
|
// Let it default
|
|
}
|
|
else
|
|
{
|
|
//Copy the value for this parameter from the argument array
|
|
//into the inparamsinstance object property
|
|
hr = (*ppInParamsInstance)->Put(bstrParamName, 0, &vParamVal, NULL);
|
|
}
|
|
}
|
|
|
|
VariantClear (&vParamVal);
|
|
}
|
|
}
|
|
|
|
VariantClear(&vIdVal);
|
|
pQualSet->Release();
|
|
pQualSet = NULL;
|
|
}
|
|
|
|
SysFreeString (bstrParamName);
|
|
bstrParamName = NULL;
|
|
|
|
if (FAILED(hr))
|
|
break;
|
|
} //while
|
|
|
|
SysFreeString (bstrId);
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// SCODE CWbemDispatchMgr::MapInParameter
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Map a in parameter
|
|
//
|
|
// PARAMETERS:
|
|
//
|
|
// pDest On successful return holds return value
|
|
// pVal The variant value to map
|
|
// lType CIMTYPE of target property value
|
|
//
|
|
//
|
|
// RETURN VALUES:
|
|
//
|
|
//***************************************************************************
|
|
|
|
HRESULT CWbemDispatchMgr::MapInParameter (
|
|
VARIANT FAR* pDest,
|
|
VARIANT FAR* pSrc,
|
|
CIMTYPE lType
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if ((NULL == pSrc) || (VT_EMPTY == V_VT(pSrc))
|
|
|| (VT_NULL == V_VT(pSrc)))
|
|
{
|
|
// Map all of these to a VT_NULL
|
|
pDest->vt = VT_NULL;
|
|
}
|
|
else if (((VT_ARRAY | VT_VARIANT) == V_VT(pSrc)) ||
|
|
((VT_ARRAY | VT_VARIANT | VT_BYREF) == V_VT(pSrc)))
|
|
{
|
|
// Arrays need to be mapped "down" to their raw form (and watch out
|
|
// for embedded objects!)
|
|
if (SUCCEEDED(hr = ConvertArray(pDest, pSrc)))
|
|
hr = MapToCIMOMObject(pDest);
|
|
}
|
|
else if ((CIM_FLAG_ARRAY & lType) &&
|
|
((VT_DISPATCH == V_VT(pSrc))
|
|
|| ((VT_DISPATCH|VT_BYREF) == V_VT(pSrc))))
|
|
{
|
|
// Look for a JScript-style IDispatch that needs to be mapped to an array
|
|
hr = ConvertDispatchToArray (pDest, pSrc, lType & ~CIM_FLAG_ARRAY);
|
|
}
|
|
else if ((VT_BYREF | VT_VARIANT) == V_VT(pSrc))
|
|
{
|
|
// May be used if the scripting language supports functions that can change
|
|
// the type of a reference. CIMOM won't do this, wo we unwrap the
|
|
// variant before proceeding
|
|
hr = MapInParameter (pDest, pSrc->pvarVal, lType);
|
|
}
|
|
else
|
|
{
|
|
// A "straightforward" value - all we have to watch for is an embedded object
|
|
// and a possible byRef
|
|
if (SUCCEEDED(hr = VariantCopy (pDest, pSrc)))
|
|
{
|
|
hr = MapToCIMOMObject(pDest);
|
|
|
|
// Is it byref - if so remove the indirection
|
|
if (VT_BYREF & V_VT(pDest))
|
|
hr = VariantChangeType(pDest, pDest, 0, V_VT(pDest) & ~VT_BYREF);
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//-------------------------------------------------------------
|
|
// CWbemDispatchMgr::RaiseException
|
|
//
|
|
// Description : signal exception to automation client
|
|
//
|
|
// Parameters : hr - HRESULT
|
|
//-------------------------------------------------------------
|
|
void CWbemDispatchMgr::RaiseException (HRESULT hr)
|
|
{
|
|
// Store the HRESULT for processing in the Invoke routine
|
|
m_hResult = hr;
|
|
|
|
// Set a WMI scripting error on this thread for the client
|
|
ICreateErrorInfo *pCreateErrorInfo = NULL;
|
|
|
|
if (SUCCEEDED (CreateErrorInfo (&pCreateErrorInfo)))
|
|
{
|
|
BSTR bsDescr = MapHresultToWmiDescription (hr);
|
|
pCreateErrorInfo->SetDescription (bsDescr);
|
|
SysFreeString (bsDescr);
|
|
pCreateErrorInfo->SetGUID (IID_ISWbemObjectEx);
|
|
pCreateErrorInfo->SetSource (L"SWbemObjectEx");
|
|
|
|
IErrorInfo *pErrorInfo = NULL;
|
|
|
|
if (SUCCEEDED (pCreateErrorInfo->QueryInterface(IID_IErrorInfo, (void**) &pErrorInfo)))
|
|
{
|
|
SetErrorInfo (0, pErrorInfo);
|
|
pErrorInfo->Release ();
|
|
}
|
|
|
|
pCreateErrorInfo->Release ();
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------
|
|
// Name : assignArrayElementToVariant
|
|
//
|
|
// Description : According to the type of the array elements,
|
|
// retrieves the requested element from the array
|
|
// into a variant
|
|
//
|
|
// Parameters : psa - pointer to the SAFEARRAY
|
|
// vt - vartype of array elements
|
|
// inx - index of the element in the array
|
|
// pvResult - resulting variant
|
|
//-------------------------------------------------------------
|
|
HRESULT assignArrayElementToVariant(SAFEARRAY *psa, VARTYPE vt, long inx, VARIANT *pvResult)
|
|
{
|
|
HRESULT hr = WBEM_S_NO_ERROR;
|
|
|
|
switch (vt)
|
|
{
|
|
case VT_I2 :
|
|
V_VT(pvResult) = VT_I2;
|
|
SafeArrayGetElement(psa, &inx, &V_I2(pvResult));
|
|
break;
|
|
case VT_I4 :
|
|
V_VT(pvResult) = VT_I4;
|
|
SafeArrayGetElement(psa, &inx, &V_I4(pvResult));
|
|
break;
|
|
case VT_R4 :
|
|
V_VT(pvResult) = VT_R4;
|
|
SafeArrayGetElement(psa, &inx, &V_R4(pvResult));
|
|
break;
|
|
case VT_R8 :
|
|
V_VT(pvResult) = VT_R8;
|
|
SafeArrayGetElement(psa, &inx, &V_R8(pvResult));
|
|
break;
|
|
case VT_DATE :
|
|
V_VT(pvResult) = VT_DATE;
|
|
SafeArrayGetElement(psa, &inx, &V_DATE(pvResult));
|
|
break;
|
|
case VT_BSTR :
|
|
V_VT(pvResult) = VT_BSTR;
|
|
SafeArrayGetElement(psa, &inx, &V_BSTR(pvResult));
|
|
break;
|
|
case VT_DISPATCH :
|
|
V_VT(pvResult) = VT_DISPATCH;
|
|
SafeArrayGetElement(psa, &inx, &V_DISPATCH(pvResult));
|
|
break;
|
|
case VT_UNKNOWN :
|
|
V_VT(pvResult) = VT_UNKNOWN;
|
|
SafeArrayGetElement(psa, &inx, &V_UNKNOWN(pvResult));
|
|
break;
|
|
case VT_BOOL :
|
|
V_VT(pvResult) = VT_BOOL;
|
|
SafeArrayGetElement(psa, &inx, &V_BOOL(pvResult));
|
|
break;
|
|
case VT_VARIANT :
|
|
{
|
|
V_VT(pvResult) = VT_BYREF | VT_VARIANT;
|
|
VARIANT *pVar = new VARIANT;
|
|
|
|
if (pVar)
|
|
{
|
|
VariantInit (pVar);
|
|
SafeArrayGetElement(psa, &inx, pVar);
|
|
V_VARIANTREF(pvResult) = pVar;
|
|
}
|
|
else
|
|
hr = WBEM_E_OUT_OF_MEMORY;
|
|
}
|
|
break;
|
|
case VT_UI1 :
|
|
V_VT(pvResult) = VT_UI1;
|
|
SafeArrayGetElement(psa, &inx, &V_UI1(pvResult));
|
|
break;
|
|
default :
|
|
V_VT(pvResult) = VT_ERROR;
|
|
break;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//-------------------------------------------------------------
|
|
// Name : CheckArrayBounds
|
|
//
|
|
// Description : Check that index is within bounds and if not
|
|
// Redim the array
|
|
//
|
|
// Parameters : psa - pointer to the SAFEARRAY
|
|
// inx - putative index
|
|
//-------------------------------------------------------------
|
|
void CheckArrayBounds(SAFEARRAY *psa, long inx)
|
|
{
|
|
long lBound, uBound;
|
|
SafeArrayGetUBound (psa, 1, &uBound);
|
|
SafeArrayGetLBound (psa, 1, &lBound);
|
|
|
|
if ((inx < lBound) || (inx > uBound))
|
|
{
|
|
// Need to redim
|
|
SAFEARRAYBOUND psaBound;
|
|
|
|
psaBound.cElements = ((inx < lBound) ?
|
|
(uBound + 1 - inx) : (inx + 1 - lBound));
|
|
|
|
psaBound.lLbound = (inx < lBound) ? inx : lBound;
|
|
SafeArrayRedim (psa, &psaBound);
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------
|
|
// Name : assignVariantToArrayElement
|
|
//
|
|
// Description : According to the type of the array elements,
|
|
// puts the new value from the variant into the
|
|
// requested element of the array
|
|
//
|
|
// Parameters : psa - pointer to the SAFEARRAY
|
|
// vt - vartype of array elements
|
|
// inx - index of the element in the array
|
|
// pvNewVal - variant containing the new value
|
|
//-------------------------------------------------------------
|
|
void assignVariantToArrayElement(SAFEARRAY *psa, VARTYPE vt, long inx, VARIANT *pvNewVal)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
|
|
// Firstly check for out-of-bounds case and grow accordingly
|
|
CheckArrayBounds (psa, inx);
|
|
|
|
switch (vt)
|
|
{
|
|
case VT_I2 :
|
|
hr = SafeArrayPutElement(psa, &inx, &V_I2(pvNewVal));
|
|
break;
|
|
case VT_I4 :
|
|
hr = SafeArrayPutElement(psa, &inx, &V_I4(pvNewVal));
|
|
break;
|
|
case VT_R4 :
|
|
hr = SafeArrayPutElement(psa, &inx, &V_R4(pvNewVal));
|
|
break;
|
|
case VT_R8 :
|
|
hr = SafeArrayPutElement(psa, &inx, &V_R8(pvNewVal));
|
|
break;
|
|
case VT_DATE :
|
|
hr = SafeArrayPutElement(psa, &inx, &V_DATE(pvNewVal));
|
|
break;
|
|
case VT_BSTR :
|
|
hr = SafeArrayPutElement(psa, &inx, V_BSTR(pvNewVal));
|
|
break;
|
|
case VT_DISPATCH :
|
|
hr = SafeArrayPutElement(psa, &inx, V_DISPATCH(pvNewVal));
|
|
break;
|
|
case VT_UNKNOWN:
|
|
hr = SafeArrayPutElement(psa, &inx, V_UNKNOWN(pvNewVal));
|
|
break;
|
|
case VT_BOOL :
|
|
hr = SafeArrayPutElement(psa, &inx, &V_BOOL(pvNewVal));
|
|
break;
|
|
case VT_VARIANT :
|
|
hr = SafeArrayPutElement(psa, &inx, V_VARIANTREF(pvNewVal));
|
|
break;
|
|
case VT_UI1 :
|
|
hr = SafeArrayPutElement(psa, &inx, &V_UI1(pvNewVal));
|
|
break;
|
|
default :
|
|
//????????????
|
|
break;
|
|
} //switch
|
|
}
|
|
|
|
|
|
//-------------------------------------------------------------
|
|
// Name : CimTypeToVtType
|
|
//
|
|
// Description : Returns the coresponding VARTYPE for
|
|
// a given CIMTYPE
|
|
// Parameters : lType - the CIMTYPE we want to convert
|
|
//-------------------------------------------------------------
|
|
VARTYPE CimTypeToVtType(CIMTYPE lType)
|
|
{
|
|
VARTYPE ret = VT_EMPTY;
|
|
|
|
if (lType & CIM_FLAG_ARRAY)
|
|
ret = VT_ARRAY;
|
|
|
|
switch(lType & ~CIM_FLAG_ARRAY)
|
|
{
|
|
case CIM_EMPTY : ret = (ret | VT_EMPTY); break;
|
|
case CIM_SINT8 : ret = (ret | VT_I2); break;
|
|
case CIM_UINT8 : ret = (ret | VT_UI1); break;
|
|
case CIM_SINT16 : ret = (ret | VT_I2); break;
|
|
case CIM_UINT16 : ret = (ret | VT_I4); break;
|
|
case CIM_SINT32 : ret = (ret | VT_I4); break;
|
|
case CIM_UINT32 : ret = (ret | VT_I4); break;
|
|
case CIM_SINT64 : ret = (ret | VT_BSTR); break;
|
|
case CIM_UINT64 : ret = (ret | VT_BSTR); break;
|
|
case CIM_REAL32 : ret = (ret | VT_R4); break;
|
|
case CIM_REAL64 : ret = (ret | VT_R8); break;
|
|
case CIM_BOOLEAN : ret = (ret | VT_BOOL); break;
|
|
case CIM_STRING : ret = (ret | VT_BSTR); break;
|
|
case CIM_DATETIME : ret = (ret | VT_BSTR); break;
|
|
case CIM_REFERENCE :ret = (ret | VT_BSTR); break;
|
|
case CIM_CHAR16 : ret = (ret | VT_I2); break;
|
|
case CIM_OBJECT : ret = (ret | VT_UNKNOWN); break;
|
|
default : ret = VT_ERROR;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
//-------------------------------------------------------------
|
|
// Name : VariantChangeByValToByRef
|
|
//
|
|
// Description : Copies a variant, while converting a "byval" to a
|
|
// "byref" if the destination type requires it
|
|
//
|
|
// Parameters : dest - destination variant to hold the result
|
|
// source - source variant to be copied
|
|
// destType - the VARTYPE required for the result.
|
|
// when this type is a BY_REF, the appropriate
|
|
// conversion is made from the source.
|
|
//-------------------------------------------------------------
|
|
HRESULT VariantChangeByValToByRef(VARIANT *dest, VARIANT *source, VARTYPE destType)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (!(destType & VT_BYREF)) //the destination is not by ref. we can do a straight copy
|
|
hr = VariantCopy(dest, source);
|
|
else
|
|
{
|
|
if ((destType & ~VT_BYREF) & VT_ARRAY)
|
|
hr = SafeArrayCopy(V_ARRAY(source), V_ARRAYREF(dest));
|
|
else
|
|
{
|
|
switch (destType & ~VT_BYREF)
|
|
{
|
|
case VT_UI1 : *V_UI1REF(dest) = V_UI1(source); break;
|
|
case VT_I2 : *V_I2REF(dest) = V_I2(source); break;
|
|
case VT_I4 : *V_I4REF(dest) = V_I4(source); break;
|
|
case VT_R4 : *V_R4REF(dest) = V_R4(source); break;
|
|
case VT_R8 : *V_R8REF(dest) = V_R8(source); break;
|
|
case VT_CY : *V_CYREF(dest) = V_CY(source); break;
|
|
case VT_BSTR : SysReAllocString(V_BSTRREF(dest), V_BSTR(source)); break;
|
|
case VT_BOOL : *V_BOOLREF(dest) = V_BOOL(source); break;
|
|
case VT_DATE : *V_DATEREF(dest) = V_DATE(source); break;
|
|
case VT_DISPATCH :
|
|
//I need to addref the object behind this interface so
|
|
//that it doesn't get released when we release the original VARIANT
|
|
//that's holding it
|
|
V_DISPATCH(source)->AddRef();
|
|
*V_DISPATCHREF(dest) = V_DISPATCH(source);
|
|
break;
|
|
case VT_UNKNOWN :
|
|
//Again, need to addref so that the object doesn't get released
|
|
V_UNKNOWN(source)->AddRef();
|
|
*V_UNKNOWNREF(dest) = V_UNKNOWN(source); break;
|
|
break;
|
|
case VT_VARIANT : hr = VariantCopy(V_VARIANTREF(dest), source); break;
|
|
default : hr = DISP_E_TYPEMISMATCH;
|
|
}
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// void CWbemDispatchMgr::EnsureClassRetrieved
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Make sure we have a class pointer
|
|
//
|
|
//***************************************************************************
|
|
|
|
void CWbemDispatchMgr::EnsureClassRetrieved ()
|
|
{
|
|
if (!m_pWbemClass)
|
|
{
|
|
CComVariant vGenusVal, vClassName;
|
|
bool bIsClass;
|
|
|
|
if (SUCCEEDED(m_pWbemObject->Get(WBEMS_SP_GENUS, 0, &vGenusVal, NULL, NULL)))
|
|
{
|
|
bIsClass = (WBEM_GENUS_CLASS == vGenusVal.lVal);
|
|
|
|
//If the object is a class, point the class pointer to it as well
|
|
if (bIsClass)
|
|
{
|
|
m_pWbemClass = m_pWbemObject;
|
|
m_pWbemClass->AddRef () ;
|
|
}
|
|
//Otherwise (it's an instance) we need to get the class
|
|
else
|
|
{
|
|
// Check we have an IWbemServices pointer
|
|
|
|
if (m_pWbemServices)
|
|
{
|
|
/*
|
|
* Note we must check that returned value is a BSTR - it could be a VT_NULL if
|
|
* the __CLASS property has not yet been set.
|
|
*/
|
|
|
|
if (SUCCEEDED(m_pWbemObject->Get(WBEMS_SP_CLASS, 0, &vClassName, NULL, NULL))
|
|
&& (VT_BSTR == V_VT(&vClassName)))
|
|
{
|
|
CComPtr<IWbemServices> pIWbemServices = m_pWbemServices->GetIWbemServices ();
|
|
|
|
if (pIWbemServices)
|
|
{
|
|
CSWbemSecurity *pSecurity = m_pWbemServices->GetSecurityInfo ();
|
|
|
|
if (pSecurity)
|
|
{
|
|
bool needToResetSecurity = false;
|
|
HANDLE hThreadToken = NULL;
|
|
|
|
if (pSecurity->SetSecurity (needToResetSecurity, hThreadToken))
|
|
pIWbemServices->GetObject (vClassName.bstrVal, 0, NULL, &m_pWbemClass, NULL);
|
|
|
|
// Restore original privileges on this thread
|
|
if (needToResetSecurity)
|
|
pSecurity->ResetSecurity (hThreadToken);
|
|
|
|
pSecurity->Release ();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// SCODE CWbemDispatchMgr::HandleError
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Provide bespoke handling of error conditions in the bolierplate
|
|
// Dispatch implementation.
|
|
//
|
|
// PARAMETERS:
|
|
//
|
|
// dispidMember, wFlags,
|
|
// pdispparams, pvarResult,
|
|
// puArgErr, All passed directly from IDispatch::Invoke
|
|
// hr The return code from the bolierplate invoke
|
|
//
|
|
// RETURN VALUES:
|
|
// The new return code (to be ultimately returned from Invoke)
|
|
//
|
|
// WBEM_S_NO_ERROR success
|
|
// WBEM_E_INVALID_PARAMETER bad input parameters
|
|
// WBEM_E_FAILED otherwise
|
|
//
|
|
//***************************************************************************
|
|
|
|
HRESULT CWbemDispatchMgr::HandleError (
|
|
DISPID dispidMember,
|
|
unsigned short wFlags,
|
|
DISPPARAMS FAR* pdispparams,
|
|
VARIANT FAR* pvarResult,
|
|
UINT FAR* puArgErr,
|
|
HRESULT hr
|
|
)
|
|
{
|
|
/*
|
|
* We are looking for GET calls on the Derivation_ property which
|
|
* supplied an argument. Since this property returns a SAFEARRAY, this may
|
|
* be legal but undetectable by the standard Dispatch mechanism. It is meaningful
|
|
* to pass an index (the interpretation is that the index specifies an offset in
|
|
* the SAFEARRAY structure that represents the derivation value).
|
|
*/
|
|
if ((dispidMember == WBEMS_DISPID_DERIVATION) && (DISP_E_NOTACOLLECTION == hr) && (1 == pdispparams->cArgs)
|
|
&& (DISPATCH_PROPERTYGET & wFlags))
|
|
{
|
|
// Looks promising - get the __DERIVATION property to try and resolve this
|
|
if (m_pWbemObject)
|
|
{
|
|
VARIANT var;
|
|
VariantInit (&var);
|
|
|
|
if (WBEM_S_NO_ERROR == m_pWbemObject->Get (WBEMS_SP_DERIVATION, 0, &var, NULL, NULL))
|
|
{
|
|
/* The value should be a VT_BSTR|VT_ARRAY */
|
|
if (((VT_ARRAY | VT_BSTR) == var.vt) && (NULL != var.parray))
|
|
{
|
|
VARIANT indexVar;
|
|
VariantInit (&indexVar);
|
|
|
|
// Attempt to coerce the index argument into a value suitable for an array index
|
|
if (S_OK == VariantChangeType (&indexVar, &pdispparams->rgvarg[0], 0, VT_I4))
|
|
{
|
|
long lArrayPropInx = V_I4(&indexVar);
|
|
|
|
// We should have a VT_ARRAY|VT_BSTR value at this point; extract the
|
|
// BSTR and set it into the VARIANT
|
|
VariantInit (pvarResult);
|
|
BSTR nameValue = NULL;
|
|
if (SUCCEEDED(hr = SafeArrayGetElement (var.parray, &lArrayPropInx, &nameValue)))
|
|
{
|
|
VariantInit (pvarResult);
|
|
pvarResult->vt = VT_BSTR;
|
|
pvarResult->bstrVal = nameValue;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = DISP_E_TYPEMISMATCH;
|
|
if (puArgErr)
|
|
*puArgErr = 0;
|
|
}
|
|
|
|
VariantClear (&indexVar);
|
|
}
|
|
}
|
|
|
|
VariantClear (&var);
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
// IDispatchEx methods
|
|
HRESULT STDMETHODCALLTYPE CWbemDispatchMgr::GetDispID(
|
|
/* [in] */ BSTR bstrName,
|
|
/* [in] */ DWORD grfdex,
|
|
/* [out] */ DISPID __RPC_FAR *pid)
|
|
{
|
|
return GetIDsOfNames(IID_NULL, &((OLECHAR *)bstrName), 1, ENGLISH_LOCALE, pid);
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// SCODE CWbemSchemaIDCache::~CWbemSchemaIDCache
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Destructor
|
|
//
|
|
//***************************************************************************
|
|
|
|
CWbemSchemaIDCache::~CWbemSchemaIDCache ()
|
|
{
|
|
DispIDNameMap::iterator next;
|
|
|
|
while ((next = m_cache.begin ()) != m_cache.end ())
|
|
next = m_cache.erase (next);
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// SCODE CWbemSchemaIDCache::GetDispID
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Attempts to resolves a set of names to DISP IDs based on WMI schema.
|
|
//
|
|
// PARAMETERS:
|
|
//
|
|
// rgszNames Array of names
|
|
// cNames Length of above array
|
|
// rgdispid Pointer to array to hold resolved DISPIDs
|
|
//
|
|
// RETURN VALUES:
|
|
//
|
|
//***************************************************************************
|
|
|
|
HRESULT CWbemSchemaIDCache::GetDispID (
|
|
LPWSTR* rgszNames,
|
|
unsigned int cNames,
|
|
DISPID* rgdispid
|
|
)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
|
|
if (0 < cNames)
|
|
{
|
|
DispIDNameMap::iterator theIterator = m_cache.find (rgszNames [0]);
|
|
|
|
if (theIterator != m_cache.end ())
|
|
{
|
|
hr = S_OK;
|
|
rgdispid [0] = (*theIterator).second;
|
|
}
|
|
else
|
|
{
|
|
if ((1 == cNames) && FindPropertyName (rgszNames [0]))
|
|
{
|
|
// Get a new dispid and add it to the cache
|
|
CWbemDispID dispId;
|
|
|
|
if (dispId.SetAsSchemaID (++m_nextId))
|
|
{
|
|
rgdispid [0] = dispId;
|
|
m_cache.insert (DispIDNameMap::value_type (rgszNames [0],
|
|
dispId));
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//If no property name matches, go on to methods
|
|
SAFEARRAY *psaInParams = NULL; //array of in parameters names
|
|
SAFEARRAY *psaOutParams = NULL; //array of out parameter names
|
|
CComPtr<IWbemClassObject> pInParams;
|
|
CComPtr<IWbemClassObject> pOutParams;
|
|
bool bMethodFound = false;
|
|
long id = 0;
|
|
bool bUnknownParameterFound = false;
|
|
|
|
//Get the names of all method parameters (in and out)
|
|
if (GetMethod (rgszNames[0], &psaInParams, &psaOutParams,
|
|
pInParams, pOutParams))
|
|
{
|
|
bMethodFound = true;
|
|
unsigned long ulParamCount;
|
|
bool ok = true;
|
|
|
|
//For each named parameter, search for it in the method parameters
|
|
for (ulParamCount=1; ok && (ulParamCount < cNames); ulParamCount++)
|
|
{
|
|
//If we find this name in the "in" parameters list, attach the id and go on
|
|
if (psaInParams && FindMemberInArray(rgszNames[ulParamCount], psaInParams))
|
|
{
|
|
if (GetIdOfMethodParameter(rgszNames[ulParamCount], //param name
|
|
pInParams,
|
|
&id))
|
|
rgdispid[ulParamCount] = id;
|
|
else
|
|
ok = false;
|
|
}
|
|
//If it's not in the "in" parameters, check the "out" parameters list
|
|
else if (psaOutParams && FindMemberInArray(rgszNames[ulParamCount], psaOutParams))
|
|
{
|
|
if (GetIdOfMethodParameter(rgszNames[ulParamCount], //param name
|
|
pOutParams,
|
|
&id))
|
|
rgdispid[ulParamCount] = id;
|
|
else
|
|
ok = false;
|
|
}
|
|
//If it's not there either - we can't find it
|
|
else
|
|
{
|
|
rgdispid[ulParamCount] = DISPID_UNKNOWN;
|
|
bUnknownParameterFound = true;
|
|
}
|
|
} //walk parameters
|
|
|
|
if (!ok)
|
|
bMethodFound = false;
|
|
}
|
|
|
|
if (psaInParams)
|
|
SafeArrayDestroy(psaInParams);
|
|
|
|
if (psaOutParams)
|
|
SafeArrayDestroy(psaOutParams);
|
|
|
|
if (!bMethodFound)
|
|
hr = E_FAIL;
|
|
else if (bUnknownParameterFound)
|
|
hr = DISP_E_UNKNOWNNAME;
|
|
else
|
|
hr = S_OK;
|
|
|
|
// Finally, if this all worked add it to the cache as a method
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
CWbemDispID dispId;
|
|
|
|
if (dispId.SetAsSchemaID (++m_nextId, false))
|
|
{
|
|
rgdispid [0] = dispId;
|
|
m_cache.insert (DispIDNameMap::value_type (rgszNames [0],
|
|
dispId));
|
|
}
|
|
else
|
|
hr = E_FAIL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//***************************************************************************
|
|
//
|
|
// bool CWbemSchemaIDCache::FindPropertyName
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Determine whether the property exists for this object and is not
|
|
// a system property
|
|
//
|
|
// PARAMETERS:
|
|
//
|
|
// bsName - name of specified property
|
|
//
|
|
// RETURN VALUES:
|
|
//
|
|
//***************************************************************************
|
|
|
|
bool CWbemSchemaIDCache::FindPropertyName(
|
|
BSTR bsName
|
|
)
|
|
{
|
|
bool result = false;;
|
|
|
|
if (m_pDispatchMgr)
|
|
{
|
|
CComPtr<IWbemClassObject> pIWbemClassObject = m_pDispatchMgr->GetObject ();
|
|
|
|
if (pIWbemClassObject)
|
|
{
|
|
//Note : This limits the support to non-system properties only !!!
|
|
LONG lFlavor = 0;
|
|
|
|
if (SUCCEEDED(pIWbemClassObject->Get(bsName, 0, NULL, NULL, &lFlavor))
|
|
&& !(WBEM_FLAVOR_ORIGIN_SYSTEM & lFlavor))
|
|
result = true;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// bool CWbemSchemaIDCache::GetMethod
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// returns the parameter names of a method in two
|
|
// safearrays - one for in and one for out
|
|
//
|
|
// PARAMETERS:
|
|
//
|
|
// bstrMethodName - name of method requested
|
|
// ppsaInParams - pointer to safearray to return
|
|
// in parameters
|
|
// ppsaOutParams - pointer to safearray to return
|
|
// out parameters
|
|
//
|
|
// RETURN VALUES:
|
|
//
|
|
//***************************************************************************
|
|
|
|
bool CWbemSchemaIDCache::GetMethod(
|
|
BSTR bstrMethodName,
|
|
SAFEARRAY **ppsaInParams,
|
|
SAFEARRAY **ppsaOutParams,
|
|
CComPtr<IWbemClassObject> & pInParamsObject,
|
|
CComPtr<IWbemClassObject> & pOutParamsObject
|
|
)
|
|
{
|
|
bool result = false;
|
|
CComPtr<IWbemClassObject> pIWbemClassObject = m_pDispatchMgr->GetClassObject ();
|
|
|
|
if (pIWbemClassObject)
|
|
{
|
|
if (SUCCEEDED(pIWbemClassObject->GetMethod(bstrMethodName, 0, &pInParamsObject, &pOutParamsObject)))
|
|
{
|
|
*ppsaInParams = NULL;
|
|
*ppsaOutParams = NULL;
|
|
bool ok = true;
|
|
|
|
if (pInParamsObject)
|
|
{
|
|
if (FAILED(pInParamsObject->GetNames(NULL, 0, NULL, ppsaInParams)))
|
|
ok = false;
|
|
}
|
|
|
|
if (ok && pOutParamsObject)
|
|
{
|
|
if (FAILED(pOutParamsObject->GetNames(NULL, 0, NULL, ppsaOutParams)))
|
|
ok = false;
|
|
}
|
|
|
|
result = ok;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// bool CWbemSchemaIDCache::GetIdOfMethodParameter
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// gets the id of a given parameter for a given method
|
|
// (this is a qualifier on the parameter property in the
|
|
// InParameters/OutParameters object)
|
|
//
|
|
// PARAMETERS:
|
|
//
|
|
// bstrParamName - parameter name
|
|
// pParams - IWbemClassObject containing parameters
|
|
// pId - pointer to long to receive the ID for this
|
|
// parameter of this method
|
|
//
|
|
// RETURN VALUES:
|
|
//
|
|
//***************************************************************************
|
|
|
|
bool CWbemSchemaIDCache::GetIdOfMethodParameter(
|
|
BSTR bstrParamName,
|
|
CComPtr<IWbemClassObject> &pParams,
|
|
long *pId
|
|
)
|
|
{
|
|
bool result = false;
|
|
|
|
if (pParams)
|
|
{
|
|
CComPtr<IWbemQualifierSet> pQualSet;
|
|
|
|
//Get qualifier set for the required parameter property
|
|
if (SUCCEEDED(pParams->GetPropertyQualifierSet(bstrParamName, &pQualSet)))
|
|
{
|
|
CComVariant vIdVal;
|
|
|
|
//Get the "id" qualifier value
|
|
if (SUCCEEDED(pQualSet->Get(L"id", 0, &vIdVal, NULL)))
|
|
{
|
|
result = true;
|
|
*pId = vIdVal.lVal;
|
|
}
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// bool CWbemSchemaIDCache::GetName
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// gets the name of the item given a DISPID
|
|
//
|
|
// PARAMETERS:
|
|
//
|
|
// dispId - id whose name we require
|
|
// bsName - the name (on successful return)
|
|
//
|
|
// RETURN VALUES:
|
|
//
|
|
//***************************************************************************
|
|
|
|
bool CWbemSchemaIDCache::GetName (
|
|
DISPID dispId,
|
|
CComBSTR & bsName
|
|
)
|
|
{
|
|
bool result = false;
|
|
|
|
DispIDNameMap::iterator theIterator = m_cache.begin ();
|
|
|
|
while (theIterator != m_cache.end ())
|
|
{
|
|
if (dispId == (*theIterator).second)
|
|
{
|
|
bsName = (*theIterator).first;
|
|
result = true;
|
|
break;
|
|
}
|
|
else
|
|
theIterator++;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// bool CWbemSchemaIDCache::FindMemberInArray
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// determine whether a name is present in a SAFEARRAY
|
|
//
|
|
// PARAMETERS:
|
|
//
|
|
// bstrName - the name we're looking for
|
|
// psaNames - SAFEARRAY we're looking in
|
|
//
|
|
// RETURN VALUES:
|
|
// true if found, false o/w
|
|
//
|
|
//***************************************************************************
|
|
|
|
bool CWbemSchemaIDCache::FindMemberInArray(BSTR bstrName, SAFEARRAY *psaNames)
|
|
{
|
|
long lUBound;
|
|
long i;
|
|
|
|
//Walk the array and check if the requested name exists
|
|
SafeArrayGetUBound(psaNames, 1, &lUBound);
|
|
|
|
for (i=0; i <= lUBound; i++)
|
|
{
|
|
CComBSTR bstrMemberName;
|
|
SafeArrayGetElement(psaNames, &i, &bstrMemberName);
|
|
|
|
if (!_wcsicmp(bstrMemberName, bstrName)) //found the property
|
|
break;
|
|
}
|
|
|
|
return (i <= lUBound);
|
|
}
|
|
|
|
|