2

I'm using an embeded IE ActiveX control in my C++ (MFC) application. The embeded IE has a JavaScript method that passes data back to my C++ application using the following (simplified) JavaScript:

function passDataTocpp()

{   
    return {key1: 134, key2:'value2'};

}

When I receive it in my C++ code, I get a VARIANT of type VT_DISPATCH. I was able to find this example that converts an array into C++ accessible data but that doesn't seem to work for an associative array (or an object.)

Any idea how to access that data?

3 Answers 3

3

IDispatch::GetIdsOfNames, IDispatch::Invoke(DISPID_PROPGET). If you don't even know which properties the object has, then query for IDispatchEx and use GetNextDispID to enumerate them.

Since you are using ATL, CComDispatchDriver is a convenient wrapper around IDispatch (but not IDispatchEx - that one you'll have to call directly). For some reason, it's not documented in MSDN. Look up CComPtr<IDispatch> specialization in atlcomcli.h, it's reasonably straightforward. CComDispatchDriver is a typedef for it.

Sign up to request clarification or add additional context in comments.

Comments

1

On C++ side the code might look like this (explained on Igor's answer):

STDMETHOD(Foo)(VARIANT vValue)
{
    ATLASSERT(vValue.vt == VT_DISPATCH);
    CComPtr<IDispatch>& pValue = reinterpret_cast<CComPtr<IDispatch>&>
        (vValue.pdispVal);
    CComVariant vItemValue;
    const HRESULT nResult = pValue.GetPropertyByName(L"key1", &vItemValue);
    // vItemValue is VT_I4 134 here

Comments

0

Following @IgorTandetnik's advice, I came up with the following method that seems to do the job (it's a pseudo-code though):

BOOL VariantToObjectProperties(CComVariant& var)
{
    HRESULT hr;

    if (var.vt != VT_DISPATCH)
        return FALSE;

    CComPtr<IDispatch> pDispatch = var.pdispVal;

    CComQIPtr<IDispatchEx> pDispatchEx;
    if(FAILED(hr = pDispatch->QueryInterface(IID_IDispatchEx, (void **)&pDispatchEx)))
        return FALSE;

    BSTR bstrName;
    DISPID dispid;

    //Assume success
    BOOL bRes = TRUE;

    //Enumerate object names
    hr = pDispatchEx->GetNextDispID(fdexEnumAll, DISPID_STARTENUM, &dispid);
    while (hr == NOERROR)
    {
        if(SUCCEEDED(hr = pDispatchEx->GetMemberName(dispid, &bstrName)))
        {
            // get DISPID of item
            DISPID dispidIndex = 0;
            LPOLESTR pIndex = reinterpret_cast<LPOLESTR>(const_cast<WCHAR *>(bstrName));
            if(SUCCEEDED(hr = pDispatch->GetIDsOfNames(IID_NULL, &pIndex, 1, LOCALE_USER_DEFAULT, &dispidIndex)))
            {
                CComVariant varItem;
                DISPPARAMS dispParams = {0};
                if(SUCCEEDED(hr = pDispatch->Invoke(dispidIndex, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET, &dispParams, &varItem, NULL, NULL)))
                {
                    //Object's property name is in 'bstrName'
                    //Object's property value is in 'varItem'
                }
                else
                {
                    ASSERT(NULL);
                    bRes = FALSE;
                }
            }
            else
            {
                ASSERT(NULL);
                bRes = FALSE;
            }
        }

        SysFreeString(bstrName);
        hr = pDispatchEx->GetNextDispID(fdexEnumAll, dispid, &dispid);
    }

    return bRes && hr == S_FALSE;
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.