How can I convert a JavaScript array() to an ATL/COM array?

前端 未结 4 479
情深已故
情深已故 2021-01-14 23:33

How can I convert a JavaScript array() to an ATL/COM array without using VBArray?

What I want to convert is a new Array() to a SAFEARRAY.

4条回答
  •  爱一瞬间的悲伤
    2021-01-15 00:13

    Here's a code to do just that (considering you already got the JS Array object as a C++ Variant), same way as Sheng Jiang suggested earlier:

    bool VariantToArray(__in const CComVariant& var, __out vector& vecVars)
    {
        // convert variant to dispatch object
        CComPtr pDispatch = VariantToDispatch(var);
        if (!pDispatch)
            return false;
    
        // invoke the object to retrieve the enumerator containing object
        CComVariant varResult;
        DISPPARAMS dispparamsNoArgs = {0};
        EXCEPINFO excepInfo = {0};
        UINT uiArgErr = (UINT)-1;  // initialize to invalid arg
        HRESULT hr = pDispatch->Invoke( DISPID_NEWENUM,
                                        IID_NULL,
                                        LOCALE_USER_DEFAULT,
                                        DISPATCH_METHOD | DISPATCH_PROPERTYGET,
                                        &dispparamsNoArgs,
                                        &varResult,
                                        &excepInfo,
                                        &uiArgErr);
        if (FAILED(hr))
            return false;
    
        // query the retrieved interface and get the enumerator object
        CComPtr pEnumVariant;
        switch (varResult.vt)
        {
            case VT_UNKNOWN:
            {
                CComPtr pUnknownResult = varResult.punkVal;
                if (!pUnknownResult)
                    return false;
                pEnumVariant = pUnknownResult; // implied query interface
            }
            break;
    
            case VT_DISPATCH:
            {
                CComPtr pDispatchResult = varResult.pdispVal;
                if (!pDispatchResult)
                    return false;
                pEnumVariant = pDispatchResult; // implied query interface
            }
            break;
    
            default:
                return false;
        }
    
        if (!pEnumVariant)
            return false;
    
        // reset enumerator to beginning of the list
        hr = pEnumVariant->Reset();
        if (FAILED(hr))
            return false;
    
        // enumerate and fetch items
        CComVariant varItem;
        ULONG uiFetched = 0;
        do 
        {
            // get next item
            hr = pEnumVariant->Next(1, &varItem, &uiFetched);
            if (FAILED(hr))
                return false;
    
            if (uiFetched == NULL) // last item
                break;
    
            // insert the item to the vector 
            vecVars.push_back(varItem);
        } while (true);
    
        return true;
    }
    

    hope that helps.

    Note:
    I saw a post where someone complained this doesn't work on IE9 (but it does on IE6,7,8), I checked it out myself - on IE9 (only) the Invoke method fail and return DISP_E_EXCEPTION.
    So i'm still looking for a better solution.

    Edited:
    Here's a code that will works on all IE browsers:

    bool VariantToArray(__in const CComVariant& var, __out vector& vecVars)
            {
                // convert variant to dispatch object
                CComPtr pDispatch = VariantToDispatch(var);
                if (!pDispatch)
                    return false;
    
                // get DISPID of length parameter from array object
                LPOLESTR sLengthName = L"length";
                DISPID dispidLength = 0;
                HRESULT hr = pDispatch->GetIDsOfNames(IID_NULL, &sLengthName, 1, LOCALE_USER_DEFAULT, &dispidLength);
                if (FAILED(hr))
                    return false;
    
                // get the number of elements using the DISPID of length parameter
                CComVariant varLength;
                DISPPARAMS dispParams = {0};
                hr = pDispatch->Invoke(dispidLength, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET, &dispParams, &varLength, NULL, NULL);
                if (FAILED(hr))
                    return false;
    
                int nLength = 0; // length of the array
                bool bGotInt = VariantToInt(varLength, nLength);
                if (!bGotInt)
                    return false;
    
                // get items of array
                for (int i=0 ; i(const_cast(strIndex.data()));
                    hr = pDispatch->GetIDsOfNames(IID_NULL, &pIndex, 1, LOCALE_USER_DEFAULT, &dispidIndex);
                    if (FAILED(hr))
                        continue;
    
                    CComVariant varItem;
                    hr = pDispatch->Invoke(dispidIndex, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET, &dispParams, &varItem, NULL, NULL);
                    if (FAILED(hr))
                        continue;
    
                    vecVars.push_back(varItem);
                }
    
                return true;
            }
    

    Enjoy :)

提交回复
热议问题