65.9K
CodeProject is changing. Read more.
Home

Resolving Variants

emptyStarIconemptyStarIconemptyStarIconemptyStarIconemptyStarIcon

0/5 (0 vote)

Jul 17, 2001

viewsIcon

66608

downloadIcon

2

Dereferincing and resolving Variants and IDispatch

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;
    }
}