Introduction
I have created a recursive function to dereference a passed VARIANT
([in]) and
to resolve IDispatch
if the contained variable in the passed VARIANT
is of type VT_DISPATCH
.
I could use VariantCopy
and/or VariantCopyInd
, but I wanted to avoid copying arrays or other types that are not expected.
Please take a look at the my function ResolveVariant()
(sorry if it is long) and let me know if you find any problems. I have done some testing and I dont see any problems (including ref. counting).
HRESULT SomeClass::get_Item(VARIANT Index, VARIANT* pVar)
{
VARIANT varOut;
VariantInit(&varOut);
HRESULT hr = ResolveVariant(&Index, &varOut);
if (!FAILED( hr )
{
switch (varOut.vt)
{
case VT_BSTR:
SomeCodeHere to prepare pVar;
break;
case VT_I4:
SomeCodeHere to prepare pVar;
break;
default:
break;
}
VariantClear(&varOut);
}
else
return hr;
}
HRESULT ResolveVariant(VARIANT* pVarIn, VARIANT* pVarOut)
{
VARIANT* tmpVarIn = pVarIn;
ULONG ByRef = 0;
while(tmpVarIn->vt == (VT_BYREF | VT_VARIANT) )
tmpVarIn = tmpVarIn->pvarVal;
if(tmpVarIn->vt & VT_BYREF)
ByRef = VT_BYREF;
switch(tmpVarIn->vt)
{
case (VT_I2): case (VT_BYREF|VT_I2):
if(ByRef)
{
if(!tmpVarIn->piVal) return E_POINTER;
pVarOut->iVal = *(tmpVarIn->piVal);
}
break;
case (VT_I4): case (VT_BYREF|VT_I4):
if(ByRef)
{
if(!tmpVarIn->plVal) return E_POINTER;
pVarOut->lVal = *(tmpVarIn->plVal);
}
break;
case (VT_BSTR): case (VT_BYREF|VT_BSTR):
if(ByRef)
{
if(!tmpVarIn->pbstrVal) return E_POINTER;
if(!*(tmpVarIn->pbstrVal) ) return E_POINTER;
pVarOut->bstrVal = *(tmpVarIn->pbstrVal);
}
break;
case (VT_DISPATCH): case (VT_BYREF|VT_DISPATCH):
if(ByRef)
{
if(!tmpVarIn->ppdispVal) return E_POINTER;
if(!*(tmpVarIn->ppdispVal) ) return E_POINTER;
pVarOut->pdispVal = *(tmpVarIn->ppdispVal);
}
break;
default:
return DISP_E_TYPEMISMATCH;
}
if(ByRef)
pVarOut->vt = (tmpVarIn->vt - ByRef);
else
*pVarOut = *tmpVarIn;
if (pVarOut->vt == VT_DISPATCH)
{
VARIANT varResolved;
DISPPARAMS dispParamsNoArgs = {NULL, NULL, 0, 0};
VariantInit(&varResolved);
if ( SUCCEEDED
pVarOut->pdispVal->Invoke(DISPID_VALUE, IID_NULL, LOCALE_SYSTEM_DEFAULT,
DISPATCH_PROPERTYGET | DISPATCH_METHOD,
&dispParamsNoArgs, &varResolved, NULL, NULL) ) )
{
ResolveVariant(&varResolved, pVarOut);
}
else
return E_FAIL;
VariantClear(&varResolved);
return S_OK;
}
else
{
HRESULT hr;
VARIANT retVar;
VariantInit(&retVar);
hr = VariantCopy(&retVar, pVarOut);
*pVarOut = retVar;
return hr;
}
}