|
|
//***************************************************************************
//
// Copyright (c) 1998-1999 Microsoft Corporation
//
// UTIL.CPP
//
// alanbos 13-Feb-98 Created.
//
// Some useful functions
//
//***************************************************************************
#include "precomp.h"
#include "assert.h"
#include "initguid.h"
#include "dispex.h"
#include <math.h>
extern CWbemErrorCache *g_pErrorCache; extern CRITICAL_SECTION g_csErrorCache;
typedef struct { VARTYPE vtOkForQual; VARTYPE vtTest; } Conversion;
Conversion QualConvertList[] = { {VT_I4, VT_I4}, {VT_I4, VT_UI1}, {VT_I4, VT_I2}, {VT_R8, VT_R4}, {VT_R8, VT_R8}, {VT_BOOL, VT_BOOL}, {VT_I4, VT_ERROR}, {VT_BSTR, VT_CY}, {VT_BSTR, VT_DATE}, {VT_BSTR, VT_BSTR}};
//***************************************************************************
//
// GetAcceptableQualType(VARTYPE vt)
//
// DESCRIPTION:
//
// Only certain types are acceptable for qualifiers. This routine takes a
// vartype and returns an acceptable conversion type. Note that if the type is
// already acceptable, then it is returned.
//
//***************************************************************************
VARTYPE GetAcceptableQualType(VARTYPE vt) { int iCnt; VARTYPE vtArrayBit = vt & VT_ARRAY; VARTYPE vtSimple = vt & ~(VT_ARRAY | VT_BYREF); int iSize = sizeof(QualConvertList) / sizeof(Conversion); for(iCnt = 0; iCnt < iSize; iCnt++) if(vtSimple == QualConvertList[iCnt].vtTest) return QualConvertList[iCnt].vtOkForQual | vtArrayBit; return VT_ILLEGAL; }
//***************************************************************************
//
// SCODE MapFromCIMOMObject
//
// Description:
//
// This function filters out embedded objects that have been passed in
// from CIMOM, ensuring they are returned to the automation environment
// as VT_DISPATCH types.
//
// Return Value:
// HRESULT NOERROR if successful, otherwise E_NOINTERFACE
// if we cannot support the requested interface.
//***************************************************************************
HRESULT MapFromCIMOMObject(CSWbemServices *pService, VARIANT *pVal, ISWbemInternalObject *pSWbemObject, BSTR propertyName, long index)
{ HRESULT hr = S_OK;
if(pVal->vt == VT_UNKNOWN) { /*
* This may be an embedded object. If it is replace by it's * scriptable equivalent. If not leave it be. */ if (pVal->punkVal) { CComQIPtr<IWbemClassObject> pIWbemClassObject (pVal->punkVal);
if (pIWbemClassObject) { // Yowzer - it's one of ours
CSWbemObject *pNew = new CSWbemObject (pService, pIWbemClassObject);
if (pNew) { CComQIPtr<IDispatch> pIDispatch (reinterpret_cast<IUnknown*>(pNew));
if (pIDispatch) { // Conversion succeeded - replace the punkVal by a pdispVal
pVal->punkVal->Release (); pVal->punkVal = NULL;
// Transfer the AddRef'd pointer from the QI call above to the Variant
pVal->pdispVal = pIDispatch.Detach (); pVal->vt = VT_DISPATCH; if (pSWbemObject) { // Our newly create CSWbemObject is an embedded object
// we need to set its site
pNew->SetSite (pSWbemObject, propertyName, index); } } else { // This should NEVER happen, but just in case
delete pNew; hr = WBEM_E_FAILED; } } else hr = WBEM_E_OUT_OF_MEMORY; } }
} else if(pVal->vt == (VT_UNKNOWN | VT_ARRAY)) { // got an array of objects. Replace the object pointers with a wrapper
// pointer
SAFEARRAYBOUND aBounds[1];
long lLBound, lUBound; SafeArrayGetLBound(pVal->parray, 1, &lLBound); SafeArrayGetUBound(pVal->parray, 1, &lUBound);
aBounds[0].cElements = lUBound - lLBound + 1; aBounds[0].lLbound = lLBound;
// Update the individual data pieces
// ================================
bool ok = true;
for(long lIndex = lLBound; ok && (lIndex <= lUBound); lIndex++) { // Load the initial data element into a VARIANT
// ============================================
CComPtr<IUnknown> pUnk;
if (FAILED(SafeArrayGetElement(pVal->parray, &lIndex, &pUnk)) || !pUnk) { ok = false; hr = WBEM_E_FAILED; } else { CComQIPtr<IWbemClassObject> pIWbemClassObject (pUnk);
if (pIWbemClassObject) { CSWbemObject *pNew = new CSWbemObject (pService, pIWbemClassObject);
if (pNew) { CComQIPtr<IDispatch> pIDispatch (reinterpret_cast<IUnknown*>(pNew));
if (pIDispatch) { if (FAILED(SafeArrayPutElement(pVal->parray, &lIndex, pIDispatch))) { hr = WBEM_E_FAILED; ok = false; } else { pVal->vt = VT_ARRAY | VT_DISPATCH;
if (pSWbemObject) { // This element is an embedded object. We must set it's site.
pNew->SetSite (pSWbemObject, propertyName, lIndex); } } } else { // This should NEVER happen, but just in case
delete pNew; hr = WBEM_E_FAILED; } } else { hr = WBEM_E_OUT_OF_MEMORY; ok = false; } } } } }
return hr; }
//***************************************************************************
//
// HRESULT MapToCIMOMObject
//
// Description:
//
// This function filters out embedded objects that have been passed in
// as VT_DISPATCH (possibly combined with VT_BYREF or VT_ARRAY). The
// object is recast inside a VT_UNKNOWN so it can be accepted by CIMOM.
//
// Parameters:
//
// pVal The input variant to check
//
// Return Value:
// HRESULT S_OK if successful
//***************************************************************************
HRESULT MapToCIMOMObject( VARIANT *pVal ) { HRESULT hRes = S_OK;
if(pVal->vt == VT_DISPATCH || (pVal->vt == (VT_DISPATCH | VT_BYREF))) { /*
* We may have an embedded object. Replace the object pointer with * a wrapper pointer. */ IDispatch *pDisp = NULL; if (V_ISBYREF(pVal) && (pVal->ppdispVal)) pDisp = *(pVal->ppdispVal); else if (VT_DISPATCH == V_VT(pVal)) pDisp = pVal->pdispVal; if (pDisp) { // If successful this will AddRef the returned interface
IWbemClassObject *pObj = CSWbemObject::GetIWbemClassObject (pDisp);
if (pObj) { // Release the dispatch pointer as we are about to remove it from the
// VARIANT, but only if it wasn't a VT_BYREF (because byrefs don't
// get AddRef'd by VariantCopy or Released by VariantClear).
if (!V_ISBYREF(pVal)) pDisp->Release ();
pVal->punkVal = pObj; pVal->vt = VT_UNKNOWN; } else { /*
* Rather than just cast IDispatch* to IUnknown*, we do a QI * with a release just in case the object has per-interface * ref counting. */ if (SUCCEEDED (hRes = pDisp->QueryInterface (IID_IUnknown, (PPVOID) &(pVal->punkVal)))) { pDisp->Release (); pVal->vt = VT_UNKNOWN; } } } } else if(pVal->vt == (VT_DISPATCH | VT_ARRAY)) { // got an array of embedded objects. Replace the object pointers with a wrapper
// pointer
SAFEARRAYBOUND aBounds[1];
long lLBound, lUBound; SafeArrayGetLBound(pVal->parray, 1, &lLBound); SafeArrayGetUBound(pVal->parray, 1, &lUBound);
aBounds[0].cElements = lUBound - lLBound + 1; aBounds[0].lLbound = lLBound;
// Update the individual data pieces
// ================================
long lIndex;
for (lIndex = lLBound; lIndex <= lUBound; lIndex++) { // Load the initial data element into a VARIANT
// ============================================
IDispatch * pDisp = NULL;
if (FAILED (hRes = SafeArrayGetElement(pVal->parray, &lIndex, &pDisp))) break; if (pDisp) { // If successful this will AddRef the returned interface
IWbemClassObject *pObj = CSWbemObject::GetIWbemClassObject (pDisp); if (pObj) { pDisp->Release (); // Balances the SafeArrayGetElement call
// Put it into the new array
// =========================
hRes = SafeArrayPutElement(pVal->parray, &lIndex, pObj); pObj->Release (); // balances CSWbemObject::GetIWbemClassObject call
if (FAILED (hRes)) break; else pVal->vt = VT_UNKNOWN | VT_ARRAY; } else { /*
* Rather than just cast IDispatch* to IUnknown*, we do a QI * with a release just in case the object has per-interface * ref counting. */ IUnknown *pUnk = NULL;
if (SUCCEEDED (hRes = pDisp->QueryInterface (IID_IUnknown, (PPVOID) &pUnk))) { pDisp->Release (); // Balances the SafeArrayGetElement call
hRes = SafeArrayPutElement(pVal->parray, &lIndex, pUnk); pUnk->Release (); // Balances the QI call
if (FAILED (hRes)) break; else pVal->vt = VT_UNKNOWN | VT_ARRAY; } else { pDisp->Release (); // Balances the SafeArrayGetElement call
break; } } } else break; }
if (lUBound < lIndex) { hRes = WBEM_S_NO_ERROR; pVal->vt = VT_UNKNOWN | VT_ARRAY; } }
return hRes; }
//***************************************************************************
//
// HRESULT SetSite
//
// Description:
//
// This function examines a VARIANT that has been successfully set as the
// value of a property to determine whether it contains any embedded objects.
// Any such objects are modified to ensure their site represents the property
// in question.
//
// Parameters:
//
// pVal The input variant to check
// pSObject Owning object of the property
// propertyName Take a wild guess
//
// Return Value:
// HRESULT S_OK if successful
//***************************************************************************
void SetSite (VARIANT *pVal, ISWbemInternalObject *pSObject, BSTR propertyName, long index) { HRESULT hRes = S_OK;
if (pVal) { if(pVal->vt == VT_DISPATCH || (pVal->vt == (VT_DISPATCH | VT_BYREF))) { // Could be an embedded object
IDispatch *pDisp = NULL; if (VT_DISPATCH == V_VT(pVal)) pDisp = pVal->pdispVal; else if (NULL != pVal->ppdispVal) pDisp = *(pVal->ppdispVal);
if (pDisp) CSWbemObject::SetSite (pDisp, pSObject, propertyName, index); } else if(pVal->vt == (VT_DISPATCH | VT_ARRAY)) { // Could be an array of embedded objects.
SAFEARRAYBOUND aBounds[1];
long lLBound, lUBound; SafeArrayGetLBound(pVal->parray, 1, &lLBound); SafeArrayGetUBound(pVal->parray, 1, &lUBound);
aBounds[0].cElements = lUBound - lLBound + 1; aBounds[0].lLbound = lLBound;
// Update the individual data pieces
// ================================
long lIndex;
for (lIndex = lLBound; lIndex <= lUBound; lIndex++) { // Load the initial data element into a VARIANT
// ============================================
IDispatch * pDisp = NULL;
if (FAILED (hRes = SafeArrayGetElement(pVal->parray, &lIndex, &pDisp))) break; if (pDisp) { CSWbemObject::SetSite (pDisp, pSObject, propertyName, lIndex); pDisp->Release (); // To balance AddRef from SafeArrayGetElement
} else break; } } } }
//***************************************************************************
//
// HRESULT ConvertArray
//
// Description:
//
// This function is applied to VARIANT arrays in order to check for certain
// restrictions imposed by CIMOM (e.g. they must be homogeneous) or perform
// conversions (certain VARIANT types have to be mapped to acceptable CIMOM
// types).
//
// Return Value:
// HRESULT S_OK if successful
//***************************************************************************
HRESULT ConvertArray(VARIANT * pDest, VARIANT * pSrc, BOOL bQualTypesOnly, VARTYPE requiredVarType) { VARTYPE vtPut; // Now is not (yet) the time to perform SWbemObject->IWbemClassObject conversion
if (VT_UNKNOWN == requiredVarType) requiredVarType = VT_DISPATCH;
// Treat these imposters just the same...
if (VT_EMPTY == requiredVarType) requiredVarType = VT_NULL;
if(pSrc == NULL || pDest == NULL) return WBEM_E_FAILED;
if (!(V_VT(pSrc) & VT_ARRAY) || !(V_VT(pSrc) & VT_VARIANT)) return WBEM_E_FAILED;
// Extract the source SAFEARRAY (how depends on whether VT_BYREF is set)
SAFEARRAY *parray = NULL;
if (VT_BYREF & V_VT(pSrc)) { if (pSrc->pparray) parray = *(pSrc->pparray); } else parray = pSrc->parray;
if (!parray) return WBEM_E_FAILED;
// Determine the size of the source array. Also make sure that the array
// only has one dimension
unsigned int uDim = SafeArrayGetDim(parray); if(uDim != 1) return WBEM_E_FAILED; // Bad array, or too many dimensions
long ix[2] = {0,0}; long lLower, lUpper; SCODE sc = SafeArrayGetLBound(parray,1,&lLower); if(sc != S_OK) return sc; sc = SafeArrayGetUBound(parray,1,&lUpper); if(sc != S_OK) return sc; int iNumElements = lUpper - lLower +1;
if(iNumElements == 0) { // Degenerate case of an empty array - simply create an empty
// copy with a VT_VARIANT type for properties
if (!bQualTypesOnly) vtPut = VT_VARIANT; else { // For qualifiers, we can hope that we've been given a candidate
// type from an existing value; otherwise we'll just have to make one up.
vtPut = (VT_NULL != requiredVarType) ? requiredVarType : VT_I4; } } else { // Use an explicit type if it was supplied
if (VT_NULL != requiredVarType) { vtPut = requiredVarType; } else { // Try an infer one from the array supplied
// Make sure all the elements of the source array are of the same type.
for(ix[0] = lLower; ix[0] <= lUpper && sc == S_OK; ix[0]++) { VARIANT var; VariantInit(&var); sc = SafeArrayGetElement(parray,ix,&var); if(sc != S_OK) return sc; VARTYPE vt = var.vt; VariantClear(&var);
if(ix[0] == lLower) vtPut = vt; else if (vtPut != vt) { // The vartype is different from that previously encountered.
// In general this is an error, but it is possible that we may
// wish to "upcast" to a common vartype in certain circumstances,
// as the automation controller may return heterogenous arrays.
// The only cases in which this applies are:
//
// 1. VT_UI1, VT_I2, VT_I4 should be upcast to the widest
// occurring type in the array.
//
// 2. VT_R4, VT_R8 should be upcast to the widest occuring type
// in the array
//
// All other cases are treated as an error.
bool error = true;
switch (vtPut) { case VT_UI1: if ((VT_I2 == vt) || (VT_I4 == vt)) { error = false; vtPut = vt; } break;
case VT_I2: if (VT_UI1 == vt) { error = false; } else if (VT_I4 == vt) { error = false; vtPut = vt; } break;
case VT_I4: if ((VT_I2 == vt) || (VT_UI1 == vt)) error = false; break;
case VT_R4: if (VT_R8 == vt) { error = false; vtPut = vt; } break;
case VT_R8: if (VT_R4 == vt) error = false; break; }
if (error) return WBEM_E_INVALID_PARAMETER; } }
// Having made our best guess, we may need to refine it
// if we are being restricted to qualifier types only
if(bQualTypesOnly) vtPut = GetAcceptableQualType(vtPut); } }
// Create a destination array of equal size
SAFEARRAYBOUND rgsabound[1]; rgsabound[0].lLbound = 0; rgsabound[0].cElements = iNumElements; SAFEARRAY * pDestArray = SafeArrayCreate(vtPut,1,rgsabound);
for(ix[0] = lLower; ix[0] <= lUpper && sc == S_OK; ix[0]++) { VARIANT var; VariantInit(&var); sc = SafeArrayGetElement(parray,ix,&var); if(sc != S_OK) { SafeArrayDestroy (pDestArray); return sc; }
if(var.vt != vtPut) { // do the conversion to the acceptable type and put that
VARIANT vTemp; VariantInit(&vTemp); LCID lcid = GetSystemDefaultLCID(); sc = VariantChangeTypeEx(&vTemp, &var, lcid, 0, vtPut);
if(sc != S_OK) { SafeArrayDestroy (pDestArray); return sc; }
if(vtPut == VT_BSTR || vtPut == VT_UNKNOWN || vtPut == VT_DISPATCH) sc = SafeArrayPutElement(pDestArray,ix,(void *)vTemp.bstrVal); else sc = SafeArrayPutElement(pDestArray,ix,(void *)&vTemp.lVal);
VariantClear(&vTemp); } else { if(vtPut == VT_BSTR || vtPut == VT_UNKNOWN || vtPut == VT_DISPATCH) sc = SafeArrayPutElement(pDestArray,ix,(void *)var.bstrVal); else sc = SafeArrayPutElement(pDestArray,ix,(void *)&var.lVal); }
VariantClear(&var); }
pDest->vt = (VT_ARRAY | vtPut); pDest->parray = pDestArray; return S_OK; }
//***************************************************************************
//
// HRESULT ConvertArrayRev
//
// Description:
//
// This function is applied to outbound VARIANT arrays in order to transform
// VARIANT arrays so that each member is a VT_VARIANT rather than a simple
// type (VT_BSTR). This is done so that certain automation environments
// (such as VBScript) can correctly interpret array values.
//
// Return Value:
// HRESULT S_OK if successful
//***************************************************************************
HRESULT ConvertArrayRev(VARIANT *pDest, VARIANT *pSrc) { if(pSrc == NULL || pDest == NULL || (0 == (pSrc->vt & VT_ARRAY))) return WBEM_E_FAILED;
// Determine the size of the source array. Also make sure that the array
// only has one dimension
unsigned int uDim = SafeArrayGetDim(pSrc->parray); if(uDim != 1) return WBEM_E_FAILED; // Bad array, or too many dimensions
long ix[2] = {0,0}; long lLower, lUpper; SCODE sc = SafeArrayGetLBound(pSrc->parray,1,&lLower); if(sc != S_OK) return sc; sc = SafeArrayGetUBound(pSrc->parray,1,&lUpper); if(sc != S_OK) return sc; int iNumElements = lUpper - lLower +1; VARTYPE vtSimple = pSrc->vt & ~VT_ARRAY; // Create a destination array of equal size
SAFEARRAYBOUND rgsabound[1]; rgsabound[0].lLbound = 0; rgsabound[0].cElements = iNumElements; SAFEARRAY *pDestArray = SafeArrayCreate(VT_VARIANT,1,rgsabound);
for(ix[0] = lLower; ix[0] <= lUpper && sc == S_OK; ix[0]++) { VARIANT var; VariantInit(&var); var.vt = vtSimple; switch (var.vt) { case VT_BSTR: { BSTR bstrVal = NULL; if (S_OK == (sc = SafeArrayGetElement (pSrc->parray, ix, &bstrVal))) { var.bstrVal = SysAllocString (bstrVal); SysFreeString (bstrVal); } } break;
case VT_DISPATCH: { IDispatch *pDispatch = NULL; if (S_OK == (sc = SafeArrayGetElement (pSrc->parray, ix, &pDispatch))) var.pdispVal = pDispatch; } break;
case VT_UNKNOWN: { IUnknown *pUnknown = NULL; if (S_OK == (sc = SafeArrayGetElement (pSrc->parray, ix, &pUnknown))) var.punkVal = pUnknown; } break;
default: { // Assume simple integer value
sc = SafeArrayGetElement (pSrc->parray, ix, &(var.lVal)); } break; }
if(sc != S_OK) return sc;
sc = SafeArrayPutElement (pDestArray, ix, &var); VariantClear(&var); }
pDest->vt = (VT_ARRAY | VT_VARIANT); pDest->parray = pDestArray; return S_OK; }
//***************************************************************************
//
// HRESULT ConvertBSTRArray
//
// Description:
//
// This function is applied to outbound SAFEARRAY's of BSTRs in order to
// transform then into SAFEARRAY's of VARIANTs (each of type VT_BSTR). This
// is required by scripting environments (such as VBScript0 which do not
// support SAFEARRAY of non-VARIANT types.
//
// Return Value:
// HRESULT S_OK if successful
//***************************************************************************
HRESULT ConvertBSTRArray(SAFEARRAY **ppDest, SAFEARRAY *pSrc) { if(pSrc == NULL || ppDest == NULL) return WBEM_E_FAILED;
// Determine the size of the source array. Also make sure that the array
// only has one dimension
unsigned int uDim = SafeArrayGetDim(pSrc); if(uDim != 1) return WBEM_E_FAILED; // Bad array, or too many dimensions
long ix[2] = {0,0}; long lLower, lUpper; SCODE sc = SafeArrayGetLBound(pSrc,1,&lLower); if(sc != S_OK) return sc; sc = SafeArrayGetUBound(pSrc,1,&lUpper); if(sc != S_OK) return sc; int iNumElements = lUpper - lLower +1; if(iNumElements == 0) return WBEM_E_FAILED;
// Create a destination array of equal size
SAFEARRAYBOUND rgsabound[1]; rgsabound[0].lLbound = 0; rgsabound[0].cElements = iNumElements; *ppDest = SafeArrayCreate(VT_VARIANT,1,rgsabound);
for(ix[0] = lLower; ix[0] <= lUpper && sc == S_OK; ix[0]++) { VARIANT var; VariantInit(&var); var.vt = VT_BSTR; BSTR bstrVal = NULL; if (S_OK == (sc = SafeArrayGetElement (pSrc, ix, &bstrVal))) { var.bstrVal = SysAllocString (bstrVal); SysFreeString (bstrVal); } if(sc != S_OK) return sc;
sc = SafeArrayPutElement (*ppDest, ix, &var); VariantClear(&var); }
return S_OK; }
//***************************************************************************
//
// HRESULT QualifierVariantChangeType
//
// DESCRIPTION:
//
// Just like VariantChangeType, but deals with arrays as well.
//
// PARAMETERS:
//
// VARIANT pvDest Destination variant
// VARIANT pvSrc Source variant (can be the same as pvDest)
// VARTYPE vtNew The type to coerce to.
//
//***************************************************************************
HRESULT QualifierVariantChangeType (VARIANT* pvDest, VARIANT* pvSrc, VARTYPE vtNew) { HRESULT hres = DISP_E_TYPEMISMATCH;
if(V_VT(pvSrc) == VT_NULL) { return VariantCopy(pvDest, pvSrc); }
if (vtNew & VT_ARRAY) { // It's an array, we have to do our own conversion
// ===============================================
if((V_VT(pvSrc) & VT_ARRAY) == 0) return DISP_E_TYPEMISMATCH;
// Create a new array
SAFEARRAY* psaSrc = V_ARRAY(pvSrc); SAFEARRAYBOUND aBounds[1];
long lLBound; SafeArrayGetLBound(psaSrc, 1, &lLBound); long lUBound; SafeArrayGetUBound(psaSrc, 1, &lUBound); aBounds[0].cElements = lUBound - lLBound + 1; aBounds[0].lLbound = lLBound;
SAFEARRAY* psaDest = SafeArrayCreate(vtNew & ~VT_ARRAY, 1, aBounds); long lIndex;
for (lIndex = lLBound; lIndex <= lUBound; lIndex++) { // Load the initial data element into a VARIANT
// ============================================
VARIANT vSrcEl; VariantInit (&vSrcEl); V_VT(&vSrcEl) = V_VT(pvSrc) & ~VT_ARRAY; SafeArrayGetElement(psaSrc, &lIndex, &V_UI1(&vSrcEl));
// Cast it to the new type
// =======================
if (SUCCEEDED (hres = VariantChangeType(&vSrcEl, &vSrcEl, 0, vtNew & ~VT_ARRAY))) { // Put it into the new array
// =========================
if(V_VT(&vSrcEl) == VT_BSTR) hres = SafeArrayPutElement(psaDest, &lIndex, V_BSTR(&vSrcEl)); else hres = SafeArrayPutElement(psaDest, &lIndex, &V_UI1(&vSrcEl)); }
VariantClear (&vSrcEl);
if (FAILED(hres)) break; }
if (lUBound < lIndex) { hres = WBEM_S_NO_ERROR; if(pvDest == pvSrc) VariantClear(pvSrc);
V_VT(pvDest) = vtNew; V_ARRAY(pvDest) = psaDest; } else SafeArrayDestroy (psaDest); } else hres = VariantChangeType(pvDest, pvSrc, VARIANT_NOVALUEPROP, vtNew);
return hres; }
//***************************************************************************
//
// void SetWbemError
//
// DESCRIPTION:
//
// For remoted WBEM COM interfaces, extra error information may be returned
// on the thread as an IWbemClassObject. This routine extracts that object
// (if found) amd stores it in thread local-storage as an ISWbemObject. The
// object can be accessed later using the SWbemLastError coclass.
//
// PARAMETERS:
//
// pService The backpointer to the CSWbemServices (used in case
// we do property/method access on the error object)
//
//***************************************************************************
void SetWbemError (CSWbemServices *pService) { EnterCriticalSection (&g_csErrorCache);
if (g_pErrorCache) g_pErrorCache->SetCurrentThreadError (pService);
LeaveCriticalSection (&g_csErrorCache); }
//***************************************************************************
//
// void ResetLastErrors
//
// DESCRIPTION:
//
// For remoted WBEM COM interfaces, extra error information may be returned
// on the thread as an IWbemClassObject. This routine clears that error. It
// also clears the ErrorInfo on the thread. This should be called at the
// start of any of the API functions
//
// PARAMETERS:
//
//***************************************************************************
void ResetLastErrors () {
SetErrorInfo(0, NULL);
EnterCriticalSection (&g_csErrorCache);
if (g_pErrorCache) g_pErrorCache->ResetCurrentThreadError ();
LeaveCriticalSection (&g_csErrorCache); }
//***************************************************************************
//
// HRESULT SetException
//
// Description:
//
// This function fills in an EXECPINFO structure using the supplied HRESULT
// and object name. The former is mapped to the Err.Description property,
// and the latter to the Err.Source property.
//
// Parameters:
//
// pExcepInfo pointer to EXCEPINFO to initialize (must not be NULL)
// hr HRESULT to map to string
// bsObjectName Name of source object that generated the error
//
// Return Value:
// HRESULT S_OK if successful
//***************************************************************************
void SetException (EXCEPINFO *pExcepInfo, HRESULT hr, BSTR bsObjectName) { if (pExcepInfo->bstrDescription) SysFreeString (pExcepInfo->bstrDescription);
pExcepInfo->bstrDescription = MapHresultToWmiDescription (hr);
if (pExcepInfo->bstrSource) SysFreeString (pExcepInfo->bstrSource);
pExcepInfo->bstrSource = SysAllocString (bsObjectName); pExcepInfo->scode = hr; }
//***************************************************************************
//
// HRESULT MapHresultToWmiDescription
//
// Description:
//
// Thin wrapper around the IWbemStatusCodeText implementation. Transforms
// an HRESULT (which may or may not be a WMI-specific error code) into a
// localized user-friendly description.
//
// Parameters:
//
// hr HRESULT to map to string
//
// Return Value:
// BSTR containing the description (or NULL).
//***************************************************************************
BSTR MapHresultToWmiDescription (HRESULT hr) { BSTR bsMessageText = NULL;
// Used as our error code translator
IWbemStatusCodeText *pErrorCodeTranslator = NULL;
HRESULT result = CoCreateInstance (CLSID_WbemStatusCodeText, 0, CLSCTX_INPROC_SERVER, IID_IWbemStatusCodeText, (LPVOID *) &pErrorCodeTranslator); if (SUCCEEDED (result)) { HRESULT hrCode = hr;
// Some WBEM success codes become Scripting error codes.
if (wbemErrTimedout == hr) hrCode = WBEM_S_TIMEDOUT; else if (wbemErrResetToDefault == hr) hrCode = WBEM_S_RESET_TO_DEFAULT;
HRESULT sc = pErrorCodeTranslator->GetErrorCodeText( hrCode, (LCID) 0, WBEMSTATUS_FORMAT_NO_NEWLINE, &bsMessageText);
pErrorCodeTranslator->Release (); }
return bsMessageText; }
//***************************************************************************
//
// HRESULT ConvertDispatchToArray
//
// DESCRIPTION:
//
// Attempt to convert from an IDispatch value to a CIM array value (property
// qualifier or context).
//
// PARAMETERS:
//
// pDest Output value
// pSrc Input value
// lCimType CIM Property type (underlying the array) - defaults to
// CIM_ILLEGAL for Qualifier & Context value mappings.
// bIsQual true iff we are mapping for a qualifier
//
// RETURN VALUES:
//
// WBEM_S_NO_ERROR success
// WBEM_E_FAILED otherwise
//
//***************************************************************************
HRESULT ConvertDispatchToArray ( VARIANT *pvDest, VARIANT *pvSrc, CIMTYPE lCimType, BOOL bIsQual, VARTYPE requiredQualifierType ) { HRESULT hr = WBEM_E_FAILED; // Default error
IDispatch * pDispatch = NULL; /*
* Extract the IDispatch pointer. NB we assume the VT of pSrc is * VT_DISPATCH (possibly combined with VT_BYREF) for this function to * have been called. */ if (VT_DISPATCH == V_VT(pvSrc)) pDispatch = pvSrc->pdispVal; else if (pvSrc->ppdispVal) pDispatch = *(pvSrc->ppdispVal); if (NULL == pDispatch) return hr;
// The expected var type of the property
VARTYPE expectedVarType = VT_ERROR; if (CIM_ILLEGAL != lCimType) expectedVarType = CimTypeToVtType (lCimType);
CComQIPtr<IDispatchEx> pIDispatchEx (pDispatch);
/*
* We use the IDispatchEx interface to iterate through the properties * of the interface. */ if (pIDispatchEx) { /*
* Looks promising, but just check if this isn't one of our objects */ CComQIPtr<ISWbemObject> pISWbemObject (pDispatch);
if (!pISWbemObject) { /*
* Start by determining how many properties there are so we can create * a suitable array. */ long propertyCount = 0; DISPID dispId = DISPID_STARTENUM; DISPPARAMS dispParams; dispParams.rgvarg = NULL; dispParams.rgdispidNamedArgs = NULL; dispParams.cArgs = 0; dispParams.cNamedArgs = 0;
while (S_OK == pIDispatchEx->GetNextDispID (fdexEnumAll, dispId, &dispId)) { if ((0 == propertyCount) && (VT_ERROR == expectedVarType)) { /*
* If we are setting an array value for a context/qualifier, the * Vartype will not yet be determined - we will use the best * we can from the first array value. */ VARIANT vPropVal; VariantInit (&vPropVal);
if (SUCCEEDED (pIDispatchEx->InvokeEx (dispId, 0, DISPATCH_PROPERTYGET, &dispParams, &vPropVal, NULL, NULL))) { if (bIsQual) expectedVarType = GetAcceptableQualType(V_VT(&vPropVal)); else if (VT_DISPATCH == V_VT(&vPropVal)) expectedVarType = VT_UNKNOWN; else expectedVarType = V_VT(&vPropVal); }
VariantClear (&vPropVal); }
//We need to check this is a "real" array entry with an index rather than some "dummy" entry
//for some non-array properties (which can happen with JScript arrays)
BSTR memberName = NULL; wchar_t *stopString=NULL; if (SUCCEEDED(pIDispatchEx->GetMemberName (dispId, &memberName))) { // Check that property name is numeric, only if it is we count it for the array size
long index = wcstol (memberName, &stopString, 10); if ((0 == wcslen (stopString))) propertyCount++; } } // Create the safearray - note that it may be empty
SAFEARRAYBOUND rgsaBound; rgsaBound.cElements = propertyCount; rgsaBound.lLbound = 0;
SAFEARRAY *pArray = SafeArrayCreate (expectedVarType, 1, &rgsaBound); if (0 < propertyCount) { // Enumerate the DISPIDs on this interface
dispId = DISPID_STARTENUM; long nextExpectedIndex = 0; HRESULT enumHr; wchar_t *stopString = NULL;
/*
* For JScript arrays, the property names are the specified indices of the * the array; these can be integer indices or they can be strings. We make * the following requirements of the array indices: * * (1) All of the indices are non-negative integers * (2) The indices start at 0 and are contiguous. */
while (S_OK == (enumHr = pIDispatchEx->GetNextDispID (fdexEnumAll, dispId, &dispId))) { BSTR memberName = NULL; if (SUCCEEDED(pIDispatchEx->GetMemberName (dispId, &memberName))) { // Check that property name is numeric
long index = wcstol (memberName, &stopString, 10);
if ((0 != wcslen (stopString))) { // Failure - cannot convert to integer
// Since JScript arrays may have additional "members" that are not real array members,
// depending on different properties that may be accessed on them, we should just
// ignore non-numeric items - instead of failing the whole thing...
SysFreeString (memberName); memberName = NULL; continue; } SysFreeString (memberName); memberName = NULL; if (index != nextExpectedIndex) { // Failure - non-contiguous array
break; }
nextExpectedIndex++;
// Extract the property
VARIANT vPropVal; VariantInit (&vPropVal); HRESULT hrInvoke; if (SUCCEEDED (hrInvoke = pIDispatchEx->InvokeEx (dispId, 0, DISPATCH_PROPERTYGET, &dispParams, &vPropVal, NULL, NULL))) { HRESULT hr2 = WBEM_E_FAILED;
// Take care of embedded objects
if ((S_OK == MapToCIMOMObject (&vPropVal)) && (S_OK == VariantChangeType (&vPropVal, &vPropVal, 0, expectedVarType))) {
switch (expectedVarType) { case VT_BSTR: hr2 = SafeArrayPutElement (pArray, &index, (void*)vPropVal.bstrVal); break;
case VT_UNKNOWN: if (!bIsQual) hr2 = SafeArrayPutElement (pArray, &index, (void*)vPropVal.punkVal); break;
default: hr2 = SafeArrayPutElement (pArray, &index, (void*)&vPropVal.lVal); break; } }
VariantClear (&vPropVal);
if (FAILED(hr2)) break; } else { // Failure - couldn't invoke method
break; } } // GetMemberName SUCCEEDED
} // while loop
if (S_FALSE == enumHr) { // Now construct the new property value using our array
VariantInit (pvDest); pvDest->vt = VT_ARRAY | expectedVarType; pvDest->parray = pArray; hr = S_OK; } else { // Something went wrong
SafeArrayDestroy (pArray); hr = WBEM_E_INVALID_PARAMETER; } } else { // Degenerate case of an empty array - simply create an empty
// copy with a VT_VARIANT type for properties
if (!bIsQual) expectedVarType = VT_VARIANT; else { // For qualifiers, we can hope that we've been given a candidate
// type from an existing value; otherwise we'll just have to make one up.
expectedVarType = (VT_NULL != requiredQualifierType) ? requiredQualifierType : VT_I4; }
VariantInit (pvDest); pvDest->vt = VT_ARRAY | expectedVarType; pvDest->parray = pArray; hr = S_OK; } } }
return hr; }
//***************************************************************************
//
// void MapNulls
//
// Description:
//
// The passing of a "null" value from script (where "null" in VB/VBS and JS
// is the keyword null, and is an undefined variable in Perl) may be interpreted
// by this API as equivalent to a default value for certain method calls.
//
// This function is used to map VT_NULL dispatch parameters to the VB standard
// realization of "missing" parameters, i.e. a VT_ERROR value whose scode is
// DISP_E_PARAMNOTFOUND.
//
// Parameters:
//
// pdispparams the input dispatch parameters
//
//***************************************************************************
void MapNulls (DISPPARAMS FAR* pdispparams) { if (pdispparams) { for (unsigned int i = 0; i < pdispparams->cArgs; i++) { VARIANTARG &v = pdispparams->rgvarg [i];
if (VT_NULL == V_VT(&v)) { v.vt = VT_ERROR; v.scode = DISP_E_PARAMNOTFOUND; } else if (((VT_VARIANT|VT_BYREF) == V_VT(&v)) && (VT_NULL == V_VT(v.pvarVal))) { v.vt = VT_ERROR; v.scode = DISP_E_PARAMNOTFOUND; } } } }
//***************************************************************************
//
// BSTR FormatAssociatorsQuery
//
// Description:
//
// Takes the parameters to an AssociatorsOf call and constructs a WQL
// query string from them.
//
// Returns: The constructed WQL query; this must be freed using
// SysFreeString by the caller.
//
// pdispparams the input dispatch parameters
//
//***************************************************************************
BSTR FormatAssociatorsQuery ( BSTR strObjectPath, BSTR strAssocClass, BSTR strResultClass, BSTR strResultRole, BSTR strRole, VARIANT_BOOL bClassesOnly, VARIANT_BOOL bSchemaOnly, BSTR strRequiredAssocQualifier, BSTR strRequiredQualifier ) { BSTR bsQuery = NULL;
// Get the length of the string:
// associators of {SourceObject} where
// AssocClass = AssocClassName
// ClassDefsOnly
// SchemaOnly
// RequiredAssocQualifier = QualifierName
// RequiredQualifier = QualifierName
// ResultClass = ClassName
// ResultRole = PropertyName
// Role = PropertyName
long queryLength = 1; // Terminating NULL
queryLength += wcslen (WBEMS_QUERY_ASSOCOF) + wcslen (WBEMS_QUERY_OPENBRACE) + wcslen (WBEMS_QUERY_CLOSEBRACE) + wcslen (strObjectPath);
bool needWhere = false;
if ((strAssocClass && (0 < wcslen (strAssocClass))) || (strResultClass && (0 < wcslen (strResultClass))) || (strResultRole && (0 < wcslen (strResultRole))) || (strRole && (0 < wcslen (strRole))) || (VARIANT_FALSE != bClassesOnly) || (VARIANT_FALSE != bSchemaOnly) || (strRequiredAssocQualifier && (0 < wcslen (strRequiredAssocQualifier))) || (strRequiredQualifier && (0 < wcslen (strRequiredQualifier)))) { needWhere = true; queryLength += wcslen (WBEMS_QUERY_WHERE); }
if (strAssocClass && (0 < wcslen (strAssocClass))) queryLength += wcslen (WBEMS_QUERY_ASSOCCLASS) + wcslen (WBEMS_QUERY_EQUALS) + wcslen (strAssocClass);
if (strResultClass && (0 < wcslen (strResultClass))) queryLength += wcslen (WBEMS_QUERY_RESCLASS) + wcslen (WBEMS_QUERY_EQUALS) + wcslen (strResultClass);
if (strResultRole && (0 < wcslen (strResultRole))) queryLength += wcslen (WBEMS_QUERY_RESROLE) + wcslen (WBEMS_QUERY_EQUALS) + wcslen (strResultRole);
if (strRole && (0 < wcslen (strRole))) queryLength += wcslen (WBEMS_QUERY_ROLE) + wcslen (WBEMS_QUERY_EQUALS) + wcslen (strRole);
if (VARIANT_FALSE != bClassesOnly) queryLength += wcslen (WBEMS_QUERY_CLASSDEFS);
if (VARIANT_FALSE != bSchemaOnly) queryLength += wcslen (WBEMS_QUERY_SCHEMAONLY);
if (strRequiredAssocQualifier && (0 < wcslen (strRequiredAssocQualifier))) queryLength += wcslen (WBEMS_QUERY_REQASSOCQ) + wcslen (WBEMS_QUERY_EQUALS) + wcslen (strRequiredAssocQualifier);
if (strRequiredQualifier && (0 < wcslen (strRequiredQualifier))) queryLength += wcslen (WBEMS_QUERY_REQQUAL) + wcslen (WBEMS_QUERY_EQUALS) + wcslen (strRequiredQualifier);
// Allocate the string and fill it in
bsQuery = SysAllocStringLen (WBEMS_QUERY_ASSOCOF, queryLength); wcscat (bsQuery, WBEMS_QUERY_OPENBRACE); wcscat (bsQuery, strObjectPath); wcscat (bsQuery, WBEMS_QUERY_CLOSEBRACE);
if (needWhere) { wcscat (bsQuery, WBEMS_QUERY_WHERE);
if (strAssocClass && (0 < wcslen (strAssocClass))) { wcscat (bsQuery, WBEMS_QUERY_ASSOCCLASS); wcscat (bsQuery, WBEMS_QUERY_EQUALS); wcscat (bsQuery, strAssocClass); }
if (strResultClass && (0 < wcslen (strResultClass))) { wcscat (bsQuery, WBEMS_QUERY_RESCLASS); wcscat (bsQuery, WBEMS_QUERY_EQUALS); wcscat (bsQuery, strResultClass); } if (strResultRole && (0 < wcslen (strResultRole))) { wcscat (bsQuery, WBEMS_QUERY_RESROLE); wcscat (bsQuery, WBEMS_QUERY_EQUALS); wcscat (bsQuery, strResultRole); }
if (strRole && (0 < wcslen (strRole))) { wcscat (bsQuery, WBEMS_QUERY_ROLE); wcscat (bsQuery, WBEMS_QUERY_EQUALS); wcscat (bsQuery, strRole); }
if (VARIANT_FALSE != bClassesOnly) wcscat (bsQuery, WBEMS_QUERY_CLASSDEFS);
if (VARIANT_FALSE != bSchemaOnly) wcscat (bsQuery, WBEMS_QUERY_SCHEMAONLY);
if (strRequiredAssocQualifier && (0 < wcslen (strRequiredAssocQualifier))) { wcscat (bsQuery, WBEMS_QUERY_REQASSOCQ); wcscat (bsQuery, WBEMS_QUERY_EQUALS); wcscat (bsQuery, strRequiredAssocQualifier); } if (strRequiredQualifier && (0 < wcslen (strRequiredQualifier))) { wcscat (bsQuery, WBEMS_QUERY_REQQUAL); wcscat (bsQuery, WBEMS_QUERY_EQUALS); wcscat (bsQuery, strRequiredQualifier); } }
return bsQuery; }
//***************************************************************************
//
// BSTR FormatReferencesQuery
//
// Description:
//
// Takes the parameters to an ReferencesOf call and constructs a WQL
// query string from them.
//
// Returns: The constructed WQL query; this must be freed using
// SysFreeString by the caller.
//
// pdispparams the input dispatch parameters
//
//***************************************************************************
BSTR FormatReferencesQuery ( BSTR strObjectPath, BSTR strResultClass, BSTR strRole, VARIANT_BOOL bClassesOnly, VARIANT_BOOL bSchemaOnly, BSTR strRequiredQualifier ) { BSTR bsQuery = NULL;
// Get the length of the string:
// references of {SourceObject} where
// ClassDefsOnly
// SchemaOnly
// RequiredQualifier = QualifierName
// ResultClass = ClassName
// Role = PropertyName
long queryLength = 1; // Terminating NULL
queryLength += wcslen (WBEMS_QUERY_REFOF) + wcslen (WBEMS_QUERY_OPENBRACE) + wcslen (WBEMS_QUERY_CLOSEBRACE) + wcslen (strObjectPath);
bool needWhere = false;
if ((strResultClass && (0 < wcslen (strResultClass))) || (strRole && (0 < wcslen (strRole))) || (VARIANT_FALSE != bClassesOnly) || (VARIANT_FALSE != bSchemaOnly) || (strRequiredQualifier && (0 < wcslen (strRequiredQualifier)))) { needWhere = true; queryLength += wcslen (WBEMS_QUERY_WHERE); }
if (strResultClass && (0 < wcslen (strResultClass))) queryLength += wcslen (WBEMS_QUERY_RESCLASS) + wcslen (WBEMS_QUERY_EQUALS) + wcslen (strResultClass);
if (strRole && (0 < wcslen (strRole))) queryLength += wcslen (WBEMS_QUERY_ROLE) + wcslen (WBEMS_QUERY_EQUALS) + wcslen (strRole);
if (VARIANT_FALSE != bClassesOnly) queryLength += wcslen (WBEMS_QUERY_CLASSDEFS);
if (VARIANT_FALSE != bSchemaOnly) queryLength += wcslen (WBEMS_QUERY_SCHEMAONLY);
if (strRequiredQualifier && (0 < wcslen (strRequiredQualifier))) queryLength += wcslen (WBEMS_QUERY_REQQUAL) + wcslen (WBEMS_QUERY_EQUALS) + wcslen (strRequiredQualifier);
// Allocate the string and fill it in
bsQuery = SysAllocStringLen (WBEMS_QUERY_REFOF, queryLength); wcscat (bsQuery, WBEMS_QUERY_OPENBRACE); wcscat (bsQuery, strObjectPath); wcscat (bsQuery, WBEMS_QUERY_CLOSEBRACE);
if (needWhere) { wcscat (bsQuery, WBEMS_QUERY_WHERE);
if (strResultClass && (0 < wcslen (strResultClass))) { wcscat (bsQuery, WBEMS_QUERY_RESCLASS); wcscat (bsQuery, WBEMS_QUERY_EQUALS); wcscat (bsQuery, strResultClass); } if (strRole && (0 < wcslen (strRole))) { wcscat (bsQuery, WBEMS_QUERY_ROLE); wcscat (bsQuery, WBEMS_QUERY_EQUALS); wcscat (bsQuery, strRole); }
if (VARIANT_FALSE != bClassesOnly) wcscat (bsQuery, WBEMS_QUERY_CLASSDEFS);
if (VARIANT_FALSE != bSchemaOnly) wcscat (bsQuery, WBEMS_QUERY_SCHEMAONLY);
if (strRequiredQualifier && (0 < wcslen (strRequiredQualifier))) { wcscat (bsQuery, WBEMS_QUERY_REQQUAL); wcscat (bsQuery, WBEMS_QUERY_EQUALS); wcscat (bsQuery, strRequiredQualifier); } }
return bsQuery; }
//***************************************************************************
//
// BSTR FormatMultiQuery
//
// Description:
//
// Takes an array of class names and formats a multi query
//
// Returns: The constructed WQL query; this must be freed using
// SysFreeString by the caller.
//
// classArray SAFEARRAY of class names
// iNumElements length of array
//
//***************************************************************************
BSTR FormatMultiQuery ( SAFEARRAY & classArray, long iNumElements ) { BSTR bsQuery = NULL; long queryLength = 1; // Terminating NULL
queryLength += (iNumElements * wcslen (WBEMS_QUERY_SELECT)) + ((iNumElements - 1) * wcslen (WBEMS_QUERY_GO));
// Work out the string lengths
HRESULT hr = S_OK;
for (long i = 0; i < iNumElements && hr == S_OK; i++) { BSTR bsName = NULL; if (SUCCEEDED(hr = SafeArrayGetElement(&classArray, &i, &bsName))) { queryLength += wcslen (bsName); SysFreeString (bsName); } }
if (SUCCEEDED(hr)) { // Allocate the string and fill it in
bsQuery = SysAllocStringLen (WBEMS_QUERY_SELECT, queryLength);
for (long i = 0; i < iNumElements && hr == S_OK; i++) { BSTR bsName = NULL; if (SUCCEEDED(hr = SafeArrayGetElement(&classArray, &i, &bsName))) { if (i > 0) wcscat (bsQuery, WBEMS_QUERY_SELECT);
wcscat (bsQuery, bsName); SysFreeString (bsName);
if (i < iNumElements - 1) wcscat (bsQuery, WBEMS_QUERY_GO); } } }
return bsQuery; }
//***************************************************************************
//
// EnsureGlobalsInitialized
//
// DESCRIPTION:
//
// Checks whether the g_pErrorCache global pointer is correctly initialized
// and, if not, assigns it appropriately.
//
//***************************************************************************
void EnsureGlobalsInitialized () { // Initialize security
CSWbemSecurity::Initialize (); EnterCriticalSection (&g_csErrorCache);
// Initlialize the error cache if proof be need be
if ( ! g_pErrorCache ) g_pErrorCache = new CWbemErrorCache (); LeaveCriticalSection (&g_csErrorCache); }
#ifdef _RDEBUG
#undef _RPrint
void _RRPrint(int line, const char *file, const char *func, const char *str, long code, const char *str2) { FILE *fp = fopen("c:/out.txt", "a");
fprintf (fp, "%s %s(%d): %s - %s %ld(0x%lx)\n", file, func, line, str, str2, code, code);
fclose(fp); } #endif
//***************************************************************************
//
// CanCoerceString
//
// DESCRIPTION:
//
// Attempts to determine whether the supplied BSTR value can be cast
// more tightly to the given CIM type.
//
// PARAMETERS:
// pVal the variant in question
// cimType the casting CIM type
//
// RETURN VALUES:
// TRUE iff the cast is OK.
//
//***************************************************************************
bool CanCoerceString ( const BSTR & bsValue, WbemCimtypeEnum cimType ) { bool result = false;
switch (cimType) { case wbemCimtypeReference: { CSWbemObjectPath objPath; result = SUCCEEDED (objPath.put_Path (bsValue)); } break;
case wbemCimtypeDatetime: { CSWbemDateTime dateTime; result = SUCCEEDED (dateTime.put_Value (bsValue)); } break;
case wbemCimtypeSint64: { __int64 ri64; result = ReadI64(bsValue, ri64); } break;
case wbemCimtypeUint64: { unsigned __int64 ri64; result = ReadUI64(bsValue, ri64); } break;
case wbemCimtypeString: result = true; break; }
return result; }
//***************************************************************************
//
// MapVariantTypeToCimType
//
// DESCRIPTION:
//
// Attempts to come up with a decent CIM type for the supplied VARIANT value.
//
// PARAMETERS:
// pVal the variant in question
// iCimType preferred cimtype (if appropriate)
//
// RETURN VALUES:
// A best match CIM type
//
//***************************************************************************
WbemCimtypeEnum MapVariantTypeToCimType ( VARIANT *pVal, CIMTYPE iCimType) { WbemCimtypeEnum cimType = wbemCimtypeSint32;
if (pVal) { VARIANT vTemp; VariantInit (&vTemp);
if ((VT_EMPTY == V_VT(pVal)) || (VT_NULL == V_VT(pVal))) cimType = (CIM_ILLEGAL == iCimType) ? wbemCimtypeSint32 : (WbemCimtypeEnum) iCimType; else if (((VT_ARRAY | VT_VARIANT) == V_VT(pVal)) || ((VT_ARRAY | VT_VARIANT | VT_BYREF) == V_VT(pVal))) { // Need to dig out the array type
if ((S_OK == ConvertArray(&vTemp, pVal)) && (S_OK == MapToCIMOMObject(&vTemp))) { // Check for empty array
long lLower, lUpper;
if ((SUCCEEDED(SafeArrayGetLBound(vTemp.parray,1,&lLower))) && (SUCCEEDED(SafeArrayGetUBound(vTemp.parray,1,&lUpper)))) { if (0 == lUpper - lLower + 1) { // For an empty array, we use wbemCimtypeSint32 unless
// we have been supplied a valid override
cimType = (CIM_ILLEGAL == iCimType) ? wbemCimtypeSint32 : (WbemCimtypeEnum) iCimType; } else { // Pick something that matches our value and override
// as best we can
cimType = GetCIMType (vTemp, iCimType, true, lLower, lUpper); } } } } else { // Look for an IDispatch that needs to be mapped to an array
if (((VT_DISPATCH == V_VT(pVal)) || ((VT_DISPATCH|VT_BYREF) == V_VT(pVal)))) { if (S_OK == ConvertDispatchToArray (&vTemp, pVal, cimType & ~CIM_FLAG_ARRAY)) { // Check for empty array
long lLower, lUpper;
if ((SUCCEEDED(SafeArrayGetLBound(vTemp.parray,1,&lLower))) && (SUCCEEDED(SafeArrayGetUBound(vTemp.parray,1,&lUpper)))) { if (0 == lUpper - lLower + 1) cimType = (CIM_ILLEGAL == iCimType) ? wbemCimtypeSint32 : (WbemCimtypeEnum) iCimType; else cimType = GetCIMType (vTemp, iCimType, true, lLower, lUpper); } } else { // Could be a plain old interface pointer for CIM_IUNKNOWN
if (SUCCEEDED(VariantCopy (&vTemp, pVal))) { if (S_OK == MapToCIMOMObject(&vTemp)) cimType = GetCIMType (vTemp, iCimType); } } } else { // The vanilla case
if (SUCCEEDED(VariantCopy (&vTemp, pVal))) { if (S_OK == MapToCIMOMObject(&vTemp)) cimType = GetCIMType (vTemp, iCimType); } } }
VariantClear (&vTemp); }
return cimType; }
//***************************************************************************
//
// GetCIMType
//
// DESCRIPTION:
//
// Attempts to come up with a decent CIM type for the supplied VARIANT,
// with (optionally) a legal CIMType "serving suggestion" to help resolve
// ambiguities.
//
// Note that this function doesn't deal with empty arrays; that has
// already been taken care of by the caller. It also can assume that the
// array is (VARTYPE) homogeneous, for the same reason.
//
// PARAMETERS:
// pVal the variant in question
// iCimType preferred cimtype (if appropriate, else wbemCimtypeIllegal)
//
// RETURN VALUES:
// A best match CIM type
//
//***************************************************************************
WbemCimtypeEnum GetCIMType ( VARIANT & var, CIMTYPE iCimType, bool bIsArray, long lLBound, long lUBound ) { WbemCimtypeEnum cimType = wbemCimtypeSint32;
switch (V_VT(&var) & ~VT_ARRAY) { /*
* Note that prior to this function being called * we will have transformed VT_DISPATCH's to * VT_UNKNOWN's. */ case VT_UNKNOWN: { /*
* Could be an embedded object or just a regular * IUnknown. */ if (bIsArray) { long ix = 0; bool bCanBeServingSuggestion = true; for(ix = lLBound; ix <= lUBound && bCanBeServingSuggestion; ix++) { CComPtr<IUnknown> pIUnknown;
if (SUCCEEDED(SafeArrayGetElement(var.parray,&ix,&pIUnknown))) { CComQIPtr<IWbemClassObject> pIWbemClassObject (pIUnknown);
if (!pIWbemClassObject) bCanBeServingSuggestion = false; } else bCanBeServingSuggestion = false; }
if (bCanBeServingSuggestion) cimType = wbemCimtypeObject; } else { CComQIPtr<IWbemClassObject> pIWbemClassObject (var.punkVal);
if (pIWbemClassObject) cimType = wbemCimtypeObject; } } break;
case VT_EMPTY: case VT_ERROR: case VT_NULL: if (CIM_ILLEGAL == iCimType) cimType = wbemCimtypeSint32; // Pick something
else cimType = (WbemCimtypeEnum) iCimType; // Anything goes
break;
case VT_VARIANT: case VT_DISPATCH: // Can't handle these with CIM types
break;
case VT_I2: { cimType = wbemCimtypeSint16; // default
switch (iCimType) { case wbemCimtypeSint32: case wbemCimtypeUint32: case wbemCimtypeSint64: case wbemCimtypeUint64: case wbemCimtypeSint16: case wbemCimtypeUint16: case wbemCimtypeChar16: cimType = (WbemCimtypeEnum) iCimType; break; // May be able to use a smaller type but
// only if the value "fits"
case wbemCimtypeSint8: if (bIsArray) { long ix = 0; bool bCanBeServingSuggestion = true; for(ix = lLBound; ix <= lUBound && bCanBeServingSuggestion; ix++) { short iVal = 0;
if (SUCCEEDED(SafeArrayGetElement(var.parray,&ix,&iVal))) { if ((iVal > 0x7F) || (-iVal > 0x80)) bCanBeServingSuggestion = false; } else bCanBeServingSuggestion = false; }
if (bCanBeServingSuggestion) cimType = (WbemCimtypeEnum) iCimType; } else { if ((var.iVal <= 0x7F) && (-var.iVal <= 0x80)) cimType = (WbemCimtypeEnum) iCimType; } break;
case wbemCimtypeUint8: if (bIsArray) { long ix = 0; bool bCanBeServingSuggestion = true; for(ix = lLBound; ix <= lUBound && bCanBeServingSuggestion; ix++) { short iVal = 0;
if (SUCCEEDED(SafeArrayGetElement(var.parray,&ix,&iVal))) { if ((iVal > 0xFF) || (iVal < 0)) bCanBeServingSuggestion = false; } else bCanBeServingSuggestion = false; }
if (bCanBeServingSuggestion) cimType = (WbemCimtypeEnum) iCimType; } else { if ((var.iVal <= 0xFF) && (var.iVal >= 0)) cimType = (WbemCimtypeEnum) iCimType; } break; } } break;
case VT_I4: { cimType = wbemCimtypeSint32; // default
switch (iCimType) { case wbemCimtypeSint32: case wbemCimtypeUint32: case wbemCimtypeSint64: case wbemCimtypeUint64: cimType = (WbemCimtypeEnum) iCimType; break; // May be able to use a smaller type but
// only if the value "fits"
case wbemCimtypeSint16: if (bIsArray) { long ix = 0; bool bCanBeServingSuggestion = true; for(ix = lLBound; ix <= lUBound && bCanBeServingSuggestion; ix++) { long iVal = 0;
if (SUCCEEDED(SafeArrayGetElement(var.parray,&ix,&iVal))) { if ((iVal > 0x7FFF) || (-iVal > 0x8000)) bCanBeServingSuggestion = false; } else bCanBeServingSuggestion = false; }
if (bCanBeServingSuggestion) cimType = (WbemCimtypeEnum) iCimType; } else { if ((var.lVal <= 0x7FFF) && (-var.lVal <= 0x8000)) cimType = (WbemCimtypeEnum) iCimType; } break;
case wbemCimtypeUint16: case wbemCimtypeChar16: if (bIsArray) { long ix = 0; bool bCanBeServingSuggestion = true; for(ix = lLBound; ix <= lUBound && bCanBeServingSuggestion; ix++) { long iVal = 0;
if (SUCCEEDED(SafeArrayGetElement(var.parray,&ix,&iVal))) { if ((iVal > 0xFFFF) || (iVal < 0)) bCanBeServingSuggestion = false; } else bCanBeServingSuggestion = false; }
if (bCanBeServingSuggestion) cimType = (WbemCimtypeEnum) iCimType; } else { if ((var.lVal <= 0xFFFF) && (var.lVal >= 0)) cimType = (WbemCimtypeEnum) iCimType; } break;
case wbemCimtypeSint8: if (bIsArray) { long ix = 0; bool bCanBeServingSuggestion = true; for(ix = lLBound; ix <= lUBound && bCanBeServingSuggestion; ix++) { long iVal = 0;
if (SUCCEEDED(SafeArrayGetElement(var.parray,&ix,&iVal))) { if ((iVal > 0x7F) || (-iVal > 0x80)) bCanBeServingSuggestion = false; } else bCanBeServingSuggestion = false; }
if (bCanBeServingSuggestion) cimType = (WbemCimtypeEnum) iCimType; } else { if ((var.lVal <= 0x7F) && (-var.lVal <= 0x80)) cimType = (WbemCimtypeEnum) iCimType; } break;
case wbemCimtypeUint8: if (bIsArray) { long ix = 0; bool bCanBeServingSuggestion = true; for(ix = lLBound; ix <= lUBound && bCanBeServingSuggestion; ix++) { long iVal = 0;
if (SUCCEEDED(SafeArrayGetElement(var.parray,&ix,&iVal))) { if ((iVal > 0xFF) || (iVal < 0)) bCanBeServingSuggestion = false; } else bCanBeServingSuggestion = false; }
if (bCanBeServingSuggestion) cimType = (WbemCimtypeEnum) iCimType; } else { if ((var.lVal <= 0xFF) && (var.lVal >= 0)) cimType = (WbemCimtypeEnum) iCimType; } break; } } break;
case VT_UI1: if ((wbemCimtypeSint16 == iCimType) || (wbemCimtypeUint16 == iCimType) || (wbemCimtypeSint8 == iCimType) || (wbemCimtypeUint8 == iCimType) || (wbemCimtypeChar16 == iCimType) || (wbemCimtypeSint32 == iCimType) || (wbemCimtypeUint32 == iCimType) || (wbemCimtypeSint64 == iCimType) || (wbemCimtypeUint64 == iCimType)) cimType = (WbemCimtypeEnum) iCimType; else cimType = wbemCimtypeUint8; break;
case VT_R8: if (wbemCimtypeReal64 == iCimType) cimType = (WbemCimtypeEnum) iCimType; else if (wbemCimtypeReal32 == iCimType) { if (bIsArray) { long ix = 0; bool bCanBeServingSuggestion = true; for(ix = lLBound; ix <= lUBound && bCanBeServingSuggestion; ix++) { double dblVal = 0;
if (SUCCEEDED(SafeArrayGetElement(var.parray,&ix,&dblVal))) { if (dblVal != (double)dblVal) bCanBeServingSuggestion = false; } else bCanBeServingSuggestion = false; }
if (bCanBeServingSuggestion) cimType = (WbemCimtypeEnum) iCimType; } else { if (var.dblVal == (float)(var.dblVal)) cimType = (WbemCimtypeEnum) iCimType; } } else cimType = wbemCimtypeReal64; break;
case VT_R4: if ((wbemCimtypeReal32 == iCimType) || (wbemCimtypeReal64 == iCimType)) cimType = (WbemCimtypeEnum) iCimType; else cimType = wbemCimtypeReal32; break;
case VT_BOOL: cimType = wbemCimtypeBoolean; break;
case VT_CY: case VT_DATE: cimType = wbemCimtypeString; // Only sensible choice
break;
case VT_BSTR: { cimType = wbemCimtypeString; // Unless we get a tighter fit
if ((wbemCimtypeString == iCimType) || (wbemCimtypeDatetime == iCimType) || (wbemCimtypeReference == iCimType) || (wbemCimtypeUint64 == iCimType) || (wbemCimtypeSint64 == iCimType)) { if (bIsArray) { long ix = 0; bool bCanBeServingSuggestion = true; for(ix = lLBound; ix <= lUBound && bCanBeServingSuggestion; ix++) { BSTR bsValue = NULL;
if (SUCCEEDED(SafeArrayGetElement(var.parray,&ix,&bsValue))) bCanBeServingSuggestion = CanCoerceString (bsValue, (WbemCimtypeEnum) iCimType); else bCanBeServingSuggestion = false; SysFreeString(bsValue); }
if (bCanBeServingSuggestion) cimType = (WbemCimtypeEnum) iCimType; } else { if (CanCoerceString (var.bstrVal, (WbemCimtypeEnum) iCimType)) cimType = (WbemCimtypeEnum) iCimType; } } } break; } return cimType; }
//***************************************************************************
//
// BOOL ReadI64
//
// DESCRIPTION:
//
// Reads a signed 64-bit value from a string
//
// PARAMETERS:
//
// LPCWSTR wsz String to read from
// __int64& i64 Destination for the value
//
//***************************************************************************
bool ReadI64(LPCWSTR wsz, __int64& ri64) { __int64 i64 = 0; const WCHAR* pwc = wsz; __int64 ia64max = ((0x7FFFFFFFFFFFFFFF / 0xA) + 0xA); int nSign = 1; if(*pwc == L'-') { nSign = -1; pwc++; } while(i64 >= 0 && i64 < ia64max && *pwc >= L'0' && *pwc <= L'9') { i64 = i64 * 10 + (*pwc - L'0'); pwc++; }
if(*pwc) return false;
if(i64 < 0) { // Special case --- largest negative number
// ========================================
if(nSign == -1 && i64 == (__int64)0x8000000000000000) { ri64 = i64; return true; } return false; }
ri64 = i64 * nSign; return true; }
//***************************************************************************
//
// BOOL ReadUI64
//
// DESCRIPTION:
//
// Reads an unsigned 64-bit value from a string
//
// PARAMETERS:
//
// LPCWSTR wsz String to read from
// unsigned __int64& i64 Destination for the value
//
//***************************************************************************
bool ReadUI64(LPCWSTR wsz, unsigned __int64& rui64) { unsigned __int64 ui64 = 0; const WCHAR* pwc = wsz;
while(ui64 < 0xFFFFFFFFFFFFFFFF / 8 && *pwc >= L'0' && *pwc <= L'9') { unsigned __int64 ui64old = ui64; ui64 = ui64 * 10 + (*pwc - L'0'); if(ui64 < ui64old) return false;
pwc++; }
if(*pwc) { return false; }
rui64 = ui64; return true; }
HRESULT BuildStringArray ( SAFEARRAY *pArray, VARIANT & var ) { HRESULT hr = WBEM_E_FAILED; SAFEARRAYBOUND rgsabound; rgsabound.lLbound = 0; long lBound = 0, uBound = -1;
if (pArray) { SafeArrayGetUBound (pArray, 1, &uBound); SafeArrayGetLBound (pArray, 1, &lBound); }
rgsabound.cElements = uBound + 1 - lBound; SAFEARRAY *pNewArray = SafeArrayCreate (VT_VARIANT, 1, &rgsabound);
if (pNewArray) { BSTR bstrName = NULL; VARIANT nameVar; VariantInit (&nameVar); bool ok = true;
/*
* If the source array is not empty, copy it over to the * new array. Wrap each member in a Variant, and ensure indexing * begins at 0. */ if (0 < rgsabound.cElements) { for (long i = 0; (i <= (rgsabound.cElements - 1)) && ok; i++) { long j = lBound + i;
if (SUCCEEDED(SafeArrayGetElement (pArray, &j, &bstrName))) { BSTR copy = SysAllocString (bstrName);
if (copy) { nameVar.vt = VT_BSTR; nameVar.bstrVal = copy; if (FAILED(SafeArrayPutElement (pNewArray, &i, &nameVar))) { ok = false; hr = WBEM_E_OUT_OF_MEMORY; }
SysFreeString (bstrName); VariantClear (&nameVar); } else { ok = false; hr = WBEM_E_OUT_OF_MEMORY; } } else ok = false; } }
if (ok) { // Now plug this array into the VARIANT
var.vt = VT_ARRAY | VT_VARIANT; var.parray = pNewArray; hr = S_OK; } else { if (pNewArray) SafeArrayDestroy (pNewArray); } } else hr = WBEM_E_OUT_OF_MEMORY;
return hr; }
HRESULT SetFromStringArray ( SAFEARRAY **ppArray, VARIANT *pVar ) { HRESULT hr = WBEM_E_FAILED;
if ((NULL == pVar) || (VT_EMPTY == V_VT(pVar)) || (VT_NULL == V_VT(pVar))) { if (*ppArray) { SafeArrayDestroy (*ppArray); *ppArray = NULL; }
hr = WBEM_S_NO_ERROR; } else if (((VT_ARRAY | VT_VARIANT) == V_VT(pVar)) || ((VT_ARRAY | VT_VARIANT | VT_BYREF) == V_VT(pVar))) { VARIANT vTemp; VariantInit (&vTemp);
if (S_OK == ConvertArray(&vTemp, pVar)) { // Is it a string array?
if (V_VT(&vTemp) == (VT_ARRAY|VT_BSTR)) { // Super - grab it out of the temporary VARIANT
if (*ppArray) SafeArrayDestroy (*ppArray); *ppArray = vTemp.parray; vTemp.vt = VT_NULL; vTemp.parray = NULL; hr = WBEM_S_NO_ERROR; } }
VariantClear(&vTemp); } else { // Look for an IDispatch that needs to be mapped to an array
if ((VT_DISPATCH == V_VT(pVar)) || ((VT_DISPATCH|VT_BYREF) == V_VT(pVar))) { VARIANT vTemp; VariantInit (&vTemp);
if (S_OK == ConvertDispatchToArray (&vTemp, pVar, wbemCimtypeString)) { // Is it a string array?
if (V_VT(&vTemp) == (VT_ARRAY|VT_BSTR)) { // Super - grab it out of the temporary VARIANT
if (*ppArray) SafeArrayDestroy (*ppArray); *ppArray = vTemp.parray; vTemp.vt = VT_NULL; vTemp.parray = NULL; hr = WBEM_S_NO_ERROR; } }
VariantClear (&vTemp); } }
return hr; }
//***************************************************************************
//
// bool IsNullOrEmptyVariant
//
// DESCRIPTION:
//
// Given a VARIANT, check if it is essentially null/empty or has
// more than one dimension
//
// PARAMETERS:
//
// pVar variant to check
//
// RETURNS:
// true if and only if the conversion was possible
//
//***************************************************************************
bool IsNullOrEmptyVariant (VARIANT & var) { bool result = false;
if ((VT_EMPTY == var.vt) || (VT_NULL == var.vt)) result = true; else if (VT_ARRAY & var.vt) { // Check if array that it is not empty or NULL
if (!(var.parray)) result = true; else { long lBound, uBound;
if ((1 != SafeArrayGetDim (var.parray)) || ( SUCCEEDED(SafeArrayGetLBound (var.parray, 1, &lBound)) && SUCCEEDED(SafeArrayGetUBound (var.parray, 1, &uBound)) && (0 == (uBound - lBound + 1)) ) ) result = true; } }
return result; }
//***************************************************************************
//
// bool RemoveElementFromArray
//
// DESCRIPTION:
//
// Given a SAFEARRAY and an index, remove the element at that index
// and shift left all following elements by one.
//
// PARAMETERS:
//
// array the SAFEARRAY in qeustion
// vt Variant type of elements in array
// iIndex index of element to remove
//
// RETURNS:
// true if and only if the conversion was possible
//
//***************************************************************************
bool RemoveElementFromArray (SAFEARRAY & array, VARTYPE vt, long iIndex) { /*
* Note: caller must ensure that the array is within bounds and that the * */
bool result = false; long lBound, uBound; if ((1== SafeArrayGetDim (&array)) && SUCCEEDED(SafeArrayGetLBound (&array, 1, &lBound)) && SUCCEEDED(SafeArrayGetUBound (&array, 1, &uBound)) && (0 < (uBound - lBound + 1)) && (iIndex <= uBound)) { bool ok = true;
for (long i = iIndex+1; ok && (i <= uBound); i++) ok = ShiftLeftElement (array, vt, i); // Finally Redim to get rid of the last element
if (ok) { SAFEARRAYBOUND rgsabound; rgsabound.lLbound = lBound; rgsabound.cElements = uBound - lBound; result = SUCCEEDED(SafeArrayRedim (&array, &rgsabound)); } else result = false; }
return result; }
//***************************************************************************
//
// bool ShiftLeftElement
//
// DESCRIPTION:
//
// Given a SAFEARRAY and an index, remove the element at that index
// and shift left all following elements by one.
//
// PARAMETERS:
//
// array the SAFEARRAY in question
// vt Variant type of elements in array
// iIndex index of element to remove
//
// RETURNS:
// true if and only if the conversion was possible
//
//***************************************************************************
bool ShiftLeftElement (SAFEARRAY & array, VARTYPE vt, long iIndex) { bool result = false; long iNewIndex = iIndex - 1;
switch (vt) { case VT_BSTR: { BSTR bstrVal;
if (SUCCEEDED(SafeArrayGetElement (&array, &iIndex, &bstrVal))) { result = SUCCEEDED(SafeArrayPutElement (&array, &iNewIndex, bstrVal)); SysFreeString (bstrVal); } } break;
case VT_UI1: { unsigned char bVal;
if (SUCCEEDED(SafeArrayGetElement (&array, &iIndex, &bVal))) result = SUCCEEDED(SafeArrayPutElement (&array, &iNewIndex, &bVal)); } break;
case VT_I2: { short iVal;
if (SUCCEEDED(SafeArrayGetElement (&array, &iIndex, &iVal))) result = SUCCEEDED(SafeArrayPutElement (&array, &iNewIndex, &iVal)); } break;
case VT_I4: { long lVal;
if (SUCCEEDED(SafeArrayGetElement (&array, &iIndex, &lVal))) result = SUCCEEDED(SafeArrayPutElement (&array, &iNewIndex, &lVal)); } break;
case VT_R4: { float fltVal;
if (SUCCEEDED(SafeArrayGetElement (&array, &iIndex, &fltVal))) result = SUCCEEDED(SafeArrayPutElement (&array, &iNewIndex, &fltVal)); } break;
case VT_R8: { double dblVal;
if (SUCCEEDED(SafeArrayGetElement (&array, &iIndex, &dblVal))) result = SUCCEEDED(SafeArrayPutElement (&array, &iNewIndex, &dblVal)); } break;
case VT_BOOL: { VARIANT_BOOL boolVal;
if (SUCCEEDED(SafeArrayGetElement (&array, &iIndex, &boolVal))) result = SUCCEEDED(SafeArrayPutElement (&array, &iNewIndex, &boolVal)); } break; }
return result; }
bool ShiftElementsToRight (SAFEARRAY & array, VARTYPE vt, long iStartIndex, long iEndIndex, long iCount) { bool result = true;
for (long iIndex = iEndIndex; result && (iIndex >= iStartIndex); iIndex--) { long iNewIndex = iIndex + iCount;
switch (vt) { case VT_BSTR: { BSTR bstrVal;
if (SUCCEEDED(SafeArrayGetElement (&array, &iIndex, &bstrVal))) { result = SUCCEEDED(SafeArrayPutElement (&array, &iNewIndex, bstrVal)); SysFreeString (bstrVal); } } break;
case VT_UI1: { unsigned char bVal;
if (SUCCEEDED(SafeArrayGetElement (&array, &iIndex, &bVal))) result = SUCCEEDED(SafeArrayPutElement (&array, &iNewIndex, &bVal)); } break;
case VT_I2: { short iVal;
if (SUCCEEDED(SafeArrayGetElement (&array, &iIndex, &iVal))) result = SUCCEEDED(SafeArrayPutElement (&array, &iNewIndex, &iVal)); } break;
case VT_I4: { long lVal;
if (SUCCEEDED(SafeArrayGetElement (&array, &iIndex, &lVal))) result = SUCCEEDED(SafeArrayPutElement (&array, &iNewIndex, &lVal)); } break;
case VT_R4: { float fltVal;
if (SUCCEEDED(SafeArrayGetElement (&array, &iIndex, &fltVal))) result = SUCCEEDED(SafeArrayPutElement (&array, &iNewIndex, &fltVal)); } break;
case VT_R8: { double dblVal;
if (SUCCEEDED(SafeArrayGetElement (&array, &iIndex, &dblVal))) result = SUCCEEDED(SafeArrayPutElement (&array, &iNewIndex, &dblVal)); } break;
case VT_BOOL: { VARIANT_BOOL boolVal;
if (SUCCEEDED(SafeArrayGetElement (&array, &iIndex, &boolVal))) result = SUCCEEDED(SafeArrayPutElement (&array, &iNewIndex, &boolVal)); } break;
case VT_DISPATCH: { IDispatch *pdispVal = NULL;
if (SUCCEEDED(SafeArrayGetElement (&array, &iIndex, &pdispVal))) { result = SUCCEEDED(SafeArrayPutElement (&array, &iNewIndex, pdispVal));
if (pdispVal) pdispVal->Release (); } } break;
case VT_UNKNOWN: { IUnknown *punkVal = NULL;
if (SUCCEEDED(SafeArrayGetElement (&array, &iIndex, &punkVal))) { result = SUCCEEDED(SafeArrayPutElement (&array, &iNewIndex, punkVal));
if (punkVal) punkVal->Release (); } } break; } }
return result; }
//***************************************************************************
//
// bool MatchBSTR
//
// DESCRIPTION:
//
// Given a VARIANT and a BSTR, find out whether the BSTR matches the
// VARIANT value (either the complete value or a member thereof).
//
// PARAMETERS:
//
// var the VARIANT in question
// bstrVal the BSTR in question
//
// RETURNS:
// true if and only if the match was made
//
//***************************************************************************
bool MatchBSTR (VARIANT & var, BSTR & bstrVal) { bool result = false; // Coerce into the underlying type of the variant
VARIANT srcVar, dstVar; srcVar.vt = VT_BSTR; srcVar.bstrVal = SysAllocString (bstrVal); VariantInit (&dstVar);
if (SUCCEEDED (VariantChangeType (&dstVar, &srcVar, 0, var.vt & ~VT_ARRAY))) { result = MatchValue (var, dstVar); VariantClear (&dstVar); }
VariantClear (&srcVar); return result; }
//***************************************************************************
//
// bool MatchUI1
//
// DESCRIPTION:
//
// Given a VARIANT and a UI1, find out whether the UI1 matches the
// VARIANT value (either the complete value or a member thereof).
//
// PARAMETERS:
//
// var the VARIANT in question
// bstrVal the BSTR in question
//
// RETURNS:
// true if and only if the match was made
//
//***************************************************************************
bool MatchUI1 (VARIANT & var, unsigned char bVal) { bool result = false; // Coerce into the underlying type of the variant
VARIANT srcVar, dstVar; srcVar.vt = VT_UI1; srcVar.bVal = bVal; VariantInit (&dstVar);
if (SUCCEEDED (VariantChangeType (&dstVar, &srcVar, 0, var.vt & ~VT_ARRAY))) { result = MatchValue (var, dstVar); VariantClear (&dstVar); }
return result; }
bool MatchBool (VARIANT & var, VARIANT_BOOL boolVal) { bool result = false; // Coerce into the underlying type of the variant
VARIANT srcVar, dstVar; srcVar.vt = VT_BOOL; srcVar.boolVal = boolVal; VariantInit (&dstVar);
if (SUCCEEDED (VariantChangeType (&dstVar, &srcVar, 0, var.vt & ~VT_ARRAY))) { result = MatchValue (var, dstVar); VariantClear (&dstVar); }
return result; }
bool MatchI2 (VARIANT & var, short iVal) { bool result = false; // Coerce into the underlying type of the variant
VARIANT srcVar, dstVar; srcVar.vt = VT_I2; srcVar.iVal = iVal; VariantInit (&dstVar);
if (SUCCEEDED (VariantChangeType (&dstVar, &srcVar, 0, var.vt & ~VT_ARRAY))) { result = MatchValue (var, dstVar); VariantClear (&dstVar); }
return result; }
bool MatchI4 (VARIANT & var, long lVal) { bool result = false; // Coerce into the underlying type of the variant
VARIANT srcVar, dstVar; srcVar.vt = VT_I4; srcVar.lVal = lVal; VariantInit (&dstVar);
if (SUCCEEDED (VariantChangeType (&dstVar, &srcVar, 0, var.vt & ~VT_ARRAY))) { result = MatchValue (var, dstVar); VariantClear (&dstVar); }
return result; }
bool MatchR4 (VARIANT & var, float fltVal) { bool result = false; // Coerce into the underlying type of the variant
VARIANT srcVar, dstVar; srcVar.vt = VT_R4; srcVar.fltVal = fltVal; VariantInit (&dstVar);
if (SUCCEEDED (VariantChangeType (&dstVar, &srcVar, 0, var.vt & ~VT_ARRAY))) { result = MatchValue (var, dstVar); VariantClear (&dstVar); }
return result; }
bool MatchR8 (VARIANT & var, double dblVal) { bool result = false; // Coerce into the underlying type of the variant
VARIANT srcVar, dstVar; srcVar.vt = VT_R8; srcVar.dblVal = dblVal; VariantInit (&dstVar);
if (SUCCEEDED (VariantChangeType (&dstVar, &srcVar, 0, var.vt & ~VT_ARRAY))) { result = MatchValue (var, dstVar); VariantClear (&dstVar); }
return result; }
//***************************************************************************
//
// bool MatchValue
//
// DESCRIPTION:
//
// Given a VARIANT (which may or may not be an array) and a second VARIANT
// (which is not an array) determine whether the second value matches the
// first or an element of the first.
//
// ASSUMPTIONS
//
// 1. The two VARIANTS have the same underlying type
// 2. The second VARIANT cannot be an array
//
// PARAMETERS:
//
// var the VARIANT in question
// bstrVal the BSTR in question
//
// RETURNS:
// true if and only if the match was made
//
//***************************************************************************
bool MatchValue (VARIANT &var1, VARIANT &var2) { bool result = false; bool bIsArray = (var1.vt & VT_ARRAY) ? true : false;
if (bIsArray) { long lBound, uBound;
if (var1.parray && (1== SafeArrayGetDim (var1.parray)) && SUCCEEDED(SafeArrayGetLBound (var1.parray, 1, &lBound)) && SUCCEEDED(SafeArrayGetUBound (var1.parray, 1, &uBound)) && (0 < (uBound - lBound + 1))) { // Break out on first match
for (long i = lBound; !result && (i <= uBound); i++) { switch (var1.vt & ~VT_ARRAY) { case VT_BSTR: { BSTR bstrVal = NULL;
if (SUCCEEDED(SafeArrayGetElement (var1.parray, &i, &bstrVal))) { result = (0 == wcscmp (bstrVal, var2.bstrVal)); SysFreeString (bstrVal); } } break;
case VT_UI1: { unsigned char bVal;
if (SUCCEEDED(SafeArrayGetElement (var1.parray, &i, &bVal))) result = (bVal == var2.bVal); } break;
case VT_I2: { short iVal; if (SUCCEEDED(SafeArrayGetElement (var1.parray, &i, &iVal))) result = (iVal == var2.iVal); } break;
case VT_I4: { long lVal; if (SUCCEEDED(SafeArrayGetElement (var1.parray, &i, &lVal))) result = (lVal == var2.lVal); } break;
case VT_R4: { float fltVal; if (SUCCEEDED(SafeArrayGetElement (var1.parray, &i, &fltVal))) result = (fltVal == var2.fltVal); } break;
case VT_R8: { double dblVal; if (SUCCEEDED(SafeArrayGetElement (var1.parray, &i, &dblVal))) result = (dblVal == var2.dblVal); } break;
case VT_BOOL: { VARIANT_BOOL boolVal; if (SUCCEEDED(SafeArrayGetElement (var1.parray, &i, &boolVal))) result = (boolVal == var2.boolVal); } break; } } } } else { switch (var1.vt) { case VT_BSTR: result = (0 == wcscmp (var1.bstrVal, var2.bstrVal)); break;
case VT_UI1: result = (var1.bVal == var2.bVal); break;
case VT_I2: result = (var1.iVal == var2.iVal); break;
case VT_I4: result = (var1.lVal == var2.lVal); break;
case VT_R4: result = (var1.fltVal == var2.fltVal); break;
case VT_R8: result = (var1.dblVal == var2.dblVal); break;
case VT_BOOL: result = (var1.boolVal == var2.boolVal); break; } }
return result; }
//***************************************************************************
//
// HRESULT WmiVariantChangeType
//
// DESCRIPTION:
//
// Given a VARIANT value and a desired CIM type, cast the value to a VARIANT
// which will be accepted when supplied to CIMOM for a property of that type.
//
// PARAMETERS:
//
// vOut the cast value
// pvIn the value to be cast
// lCimType the required CIM type
//
// RETURNS:
// S_OK if succeeded, WBEM_E_TYPE_MISMATCH if not
//
//***************************************************************************
// NTBUG#21788: IA64 workaround until compiler version 2210 or greater drop.
HRESULT WmiVariantChangeType ( VARIANT & vOut, VARIANT *pvIn, CIMTYPE lCimType ) { HRESULT hr = WBEM_E_TYPE_MISMATCH; VariantInit (&vOut); // First we check for a NULL value, as these are easy
if ((NULL == pvIn) || VT_EMPTY == V_VT(pvIn) || VT_NULL == V_VT(pvIn) || ((VT_ERROR == V_VT(pvIn)) && (DISP_E_PARAMNOTFOUND == pvIn->scode))) { ZeroMemory( &vOut, sizeof( VARIANT ) ); vOut.vt = VT_NULL; hr = S_OK; } else { // The kind of variant we will need to construct
VARTYPE vtOut = CimTypeToVtType (lCimType); // The VARTYPE we've been given
VARTYPE vtIn = V_VT(pvIn);
if (vtOut == vtIn) { // Life is easy
hr = VariantCopy (&vOut, pvIn); } else { // Types do not match - we have some work to to
if (CIM_FLAG_ARRAY & lCimType) { /*
* Check for a regular SAFEARRAY type value first; if that fails * then look for an IDispatch-style array value. */ if (((VT_ARRAY | VT_VARIANT) == vtIn) || ((VT_ARRAY | VT_VARIANT | VT_BYREF) == vtIn)) { SAFEARRAY *parray = (VT_BYREF & vtIn) ? *(pvIn->pparray) : pvIn->parray;
hr = WmiConvertSafeArray (vOut, parray, lCimType & ~VT_ARRAY); } else if ((VT_DISPATCH == vtIn) || ((VT_DISPATCH|VT_BYREF) == vtIn)) { CComPtr<IDispatch> pIDispatch = (VT_BYREF & vtIn) ? *(pvIn->ppdispVal) : pvIn->pdispVal; hr = WmiConvertDispatchArray (vOut, pIDispatch, lCimType & ~VT_ARRAY); } else if (((VT_ARRAY | VT_DISPATCH) == vtIn) || ((VT_ARRAY | VT_DISPATCH | VT_BYREF) == vtIn)) { if (SUCCEEDED(hr = VariantCopy (&vOut, pvIn))) hr = MapToCIMOMObject (&vOut); } } else { switch (lCimType) { case wbemCimtypeSint8: { /*
* These are represented by * a VT_I2, but we need to be careful about sign * extension from shorter types taking us "out of range". */ if (SUCCEEDED(hr = VariantChangeType (&vOut, pvIn, 0, vtOut))) { // Did we get sign extended?
if ((VT_UI1 == vtIn) || (VT_BOOL == vtIn)) vOut.lVal &= 0x000000FF; } else { // If we can't change the type, try the one we're given
hr = VariantCopy (&vOut, pvIn); } } break;
case wbemCimtypeSint64: case wbemCimtypeUint64: { /*
* These types are realized as VT_BSTR in CIM terms, which means * that VariantChangeType will almost always succeed but not * leave us with a valid numeric value. To be consistent with other * numeric types we should round up floating/double * values to the next largest integer (as is done by VariantChangeType * for VT_R8 to numeric conversion). */
if (VT_R8 == V_VT(pvIn)) { // if (SUCCEEDED(hr = VariantCopy (&vOut, pvIn)))
{ vOut.vt = pvIn->vt; // Round it up
vOut.dblVal = (pvIn->dblVal + 0.5) > ceil(pvIn->dblVal) ? ceil(pvIn->dblVal) : ceil(pvIn->dblVal - 0.5); // Convert to string
int dec = 0; int sign = 0; char *pDbl = _fcvt (vOut.dblVal, 0, &dec, &sign); if (pDbl) { size_t len = strlen (pDbl);
/*
* Having rounded up to an integer, we really expect * there to be no fractional component to the number * returned by _fcvt. */ if (dec == len) { /*
* Now convert to a wide string - remember the * sign bit! */ if (0 != sign) len += 1;
wchar_t *pValue = new wchar_t [len + 1];
if (pValue) { if (0 != sign) { pValue [0] = L'-'; mbstowcs (pValue+1, pDbl, len); } else mbstowcs (pValue, pDbl, len);
pValue [len] = NULL;
// Now set it in the variant
vOut.bstrVal = SysAllocString (pValue); vOut.vt = VT_BSTR;
delete [] pValue; hr = S_OK; } } } } } else hr = VariantChangeType (&vOut, pvIn, 0, vtOut); if (FAILED(hr)) { // If we can't change the type, try the one we're given
hr = VariantCopy (&vOut, pvIn); } } break;
case wbemCimtypeUint8: case wbemCimtypeSint16: case wbemCimtypeSint32: case wbemCimtypeReal32: case wbemCimtypeReal64: case wbemCimtypeString: case wbemCimtypeDatetime: case wbemCimtypeBoolean: case wbemCimtypeReference: { /*
* These types have a "prefect" fit to their * corresponding Variant type. */ if (FAILED(hr = VariantChangeType (&vOut, pvIn, 0, vtOut))) hr = VariantCopy (&vOut, pvIn); } break; case wbemCimtypeUint32: { if (FAILED(hr = VariantChangeType (&vOut, pvIn, 0, vtOut))) { /*
* Watch for the case where we have been given a VT_R8 * in lieu of a "large" unsigned 32-bit integer value. */ if (VT_R8 == V_VT(pvIn)) { // Is this "really" an integer?
if (floor (pvIn->dblVal) == ceil(pvIn->dblVal)) { // Fool it by casting to a UI4 - all we need is the bit pattern
if (SUCCEEDED(hr = VarUI4FromR8 (pvIn->dblVal, (ULONG*)&vOut.lVal))) vOut.vt = VT_I4; } } }
// If no joy thus far, just copy and have done with it
if (FAILED(hr)) hr = VariantCopy (&vOut, pvIn); } break; case wbemCimtypeChar16: case wbemCimtypeUint16: { /*
* These types are represented by * a VT_I4, but we need to be careful about sign * extension taking us "out of range". */ if (SUCCEEDED(hr = VariantChangeType (&vOut, pvIn, 0, vtOut))) { // Did we get sign extended from a shorter type?
if ((VT_I2 == vtIn) || (VT_UI1 == vtIn) || (VT_BOOL == vtIn)) vOut.lVal &= 0x0000FFFF; } else hr = VariantCopy (&vOut, pvIn); } break; case wbemCimtypeObject: { /*
* We're looking for an embedded object */ if (SUCCEEDED(hr = VariantCopy (&vOut, pvIn))) hr = MapToCIMOMObject (&vOut); } break; } } } }
return hr; }
//***************************************************************************
//
// HRESULT WmiConvertSafeArray
//
// Description:
//
// This function is applied to VARIANT arrays in order to check for certain
// restrictions imposed by CIMOM (e.g. they must be homogeneous) or perform
// conversions (certain VARIANT types have to be mapped to acceptable CIMOM
// types).
//
// Return Value:
// HRESULT S_OK if successful
//***************************************************************************
HRESULT WmiConvertSafeArray(VARIANT &vOut, SAFEARRAY *parray, CIMTYPE lCimType) { HRESULT hr = WBEM_E_FAILED; VARTYPE vtPut; // The underlying type of the target array
long lLower, lUpper; if (parray) { if (GetSafeArrayDimensions (*parray, lLower, lUpper)) { int iNumElements = lUpper - lLower +1;
/*
* For empty arrays, it suffices to create a empty array of * VT_VARIANT's. Otherwise we need to build what WMI is expecting. */ vtPut = (iNumElements == 0) ? VT_VARIANT : CimTypeToVtType (lCimType); // Now create a destination array of the required size
SAFEARRAYBOUND rgsabound[1]; rgsabound[0].lLbound = 0; rgsabound[0].cElements = iNumElements; SAFEARRAY * pDestArray = SafeArrayCreate(vtPut, 1, rgsabound);
if (pDestArray) { bool ok = true;
for(long i = lLower; (i <= lUpper) && ok; i++) { VARIANT var; VariantInit(&var); if (SUCCEEDED(SafeArrayGetElement (parray, &i, &var))) { // do the conversion to the acceptable type and put that
VARIANT vWMI; VariantInit(&vWMI);
if (SUCCEEDED(hr = WmiVariantChangeType (vWMI, &var, lCimType))) { if(V_VT(&vWMI) == VT_BSTR || V_VT(&vWMI) == VT_UNKNOWN || V_VT(&vWMI) == VT_DISPATCH) ok = (S_OK == SafeArrayPutElement(pDestArray, &i, (void *)vWMI.bstrVal)); else ok = (S_OK == SafeArrayPutElement(pDestArray, &i, (void *)&vWMI.lVal)); } VariantClear (&vWMI); } else ok = false;
VariantClear(&var); }
if (!ok) { SafeArrayDestroy (pDestArray); } else { vOut.vt = (VT_ARRAY | vtPut); vOut.parray = pDestArray; hr = S_OK; } } else hr = WBEM_E_OUT_OF_MEMORY; } }
return hr; }
//***************************************************************************
//
// HRESULT WmiConvertDispatchArray
//
// DESCRIPTION:
//
// Attempt to convert from an IDispatch value to a CIM array value (property
// qualifier or context).
//
// PARAMETERS:
//
// pDest Output value
// pSrc Input value
// lCimType CIM Property type (underlying the array) - defaults to
// CIM_ILLEGAL for Qualifier & Context value mappings.
// bIsQual true iff we are mapping for a qualifier
//
// RETURN VALUES:
//
// WBEM_S_NO_ERROR success
// WBEM_E_FAILED otherwise
//
//***************************************************************************
HRESULT WmiConvertDispatchArray ( VARIANT &vOut, CComPtr<IDispatch> & pIDispatch, CIMTYPE lCimType ) { HRESULT hr = WBEM_E_FAILED; // Default error
if (pIDispatch) { /*
* Looking for an IDispatchEx to iterate through the properties * of the array. */ CComQIPtr<IDispatchEx> pIDispatchEx (pIDispatch);
if (pIDispatchEx) { /*
* Looks promising, but just check if this isn't one of our objects */ CComQIPtr<ISWbemObject> pISWbemObject (pIDispatch);
if (!pISWbemObject) { /*
* Start by determining how many properties there are so we can create * a suitable array. */ long iNumElements = 0; DISPID dispId = DISPID_STARTENUM; while (S_OK == pIDispatchEx->GetNextDispID (fdexEnumAll, dispId, &dispId)) { //We need to check this is a "real" array entry with an index rather than some "dummy" entry
//for some non-array properties (which can happen with JScript arrays)
BSTR memberName = NULL; wchar_t *stopString=NULL; if (SUCCEEDED(pIDispatchEx->GetMemberName (dispId, &memberName))) { // Check that property name is numeric, only if it is we count it for the array size
long index = wcstol (memberName, &stopString, 10); if ((0 == wcslen (stopString))) iNumElements++; } }
/*
* For empty arrays, it suffices to create a empty array of * VT_VARIANT's. Otherwise we need to build what WMI is expecting. */ VARTYPE vtPut = (iNumElements == 0) ? VT_VARIANT : CimTypeToVtType (lCimType);
// Create the safearray - note that it may be empty
SAFEARRAYBOUND rgsaBound; rgsaBound.cElements = iNumElements; rgsaBound.lLbound = 0;
SAFEARRAY *pDestArray = SafeArrayCreate (vtPut, 1, &rgsaBound); if (pDestArray) { bool ok = true;
if (0 < iNumElements) { // Enumerate the DISPIDs on this interface
dispId = DISPID_STARTENUM; DISPPARAMS dispParams; dispParams.rgvarg = NULL; dispParams.rgdispidNamedArgs = NULL; dispParams.cArgs = 0; dispParams.cNamedArgs = 0;
long nextExpectedIndex = 0; HRESULT enumHr; wchar_t *stopString = NULL;
/*
* For JScript arrays, the property names are the specified indices of the * the array; these can be integer indices or they can be strings. We make * the following requirements of the array indices: * * (1) All of the indices are non-negative integers * (2) The indices start at 0 and are contiguous. */
while (ok && SUCCEEDED(enumHr = pIDispatchEx->GetNextDispID (fdexEnumAll, dispId, &dispId))) { if (S_FALSE == enumHr) { // We have reached the end
break; }
CComBSTR memberName;
if (SUCCEEDED(pIDispatchEx->GetMemberName (dispId, &memberName))) { // Check that property name is numeric
long i = wcstol (memberName, &stopString, 10);
if ((0 != wcslen (stopString))) { // Failure - cannot convert to integer
// Since JScript arrays may have additional "members" that are not real array members,
// depending on different properties that may be accessed on them, we should just
// ignore non-numeric items - instead of failing the whole thing...
continue; } else if (i != nextExpectedIndex) { // Failure - non-contiguous array
ok = false; } else { nextExpectedIndex++;
// Extract the property
VARIANT var; VariantInit (&var); if (SUCCEEDED (pIDispatchEx->InvokeEx (dispId, 0, DISPATCH_PROPERTYGET, &dispParams, &var, NULL, NULL))) { // do the conversion to the acceptable type and put that
VARIANT vWMI; VariantInit(&vWMI);
if (SUCCEEDED(hr = WmiVariantChangeType (vWMI, &var, lCimType))) { if(V_VT(&vWMI) == VT_BSTR || V_VT(&vWMI) == VT_UNKNOWN || V_VT(&vWMI) == VT_DISPATCH) ok = (S_OK == SafeArrayPutElement(pDestArray, &i, (void *)vWMI.bstrVal)); else ok = (S_OK == SafeArrayPutElement(pDestArray, &i, (void *)&vWMI.lVal)); } VariantClear (&vWMI); } else ok = false; } } else { // Failure - couldn't invoke method
ok = false; } } }
if (ok) { // Now construct the new property value using our array
vOut.vt = VT_ARRAY | vtPut; vOut.parray = pDestArray; hr = S_OK; } else SafeArrayDestroy (pDestArray); } else hr = WBEM_E_OUT_OF_MEMORY; } } }
return hr; }
bool GetSafeArrayDimensions (SAFEARRAY &sArray, long &lLower, long &lUpper) { bool result = false;
// Must be 1-dimensional
if (1 == SafeArrayGetDim(&sArray)) { if (SUCCEEDED(SafeArrayGetLBound(&sArray,1,&lLower)) && SUCCEEDED(SafeArrayGetUBound(&sArray,1,&lUpper))) result = true; }
return result; }
|