javascript - 如何将 JavaScript array() 转换为 ATL/COM 数组?

标签 javascript c++ arrays atl

如何在不使用 VBArray 的情况下将 JavaScript array() 转换为 ATL/COM 数组?

我想将一个新的 Array() 转换为一个 SAFEARRAY。

最佳答案

这里有一段代码可以做到这一点(考虑到您已经将 JS Array 对象作为 C++ 变体),与 Sheng Jiang 之前建议的方法相同:

bool VariantToArray(__in const CComVariant& var, __out vector<CComVariant>& vecVars)
{
    // convert variant to dispatch object
    CComPtr<IDispatch> 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<IEnumVARIANT> pEnumVariant;
    switch (varResult.vt)
    {
        case VT_UNKNOWN:
        {
            CComPtr<IUnknown> pUnknownResult = varResult.punkVal;
            if (!pUnknownResult)
                return false;
            pEnumVariant = pUnknownResult; // implied query interface
        }
        break;

        case VT_DISPATCH:
        {
            CComPtr<IDispatch> 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;
}

希望对您有所帮助。

注意:
我看到一个帖子 someone complained this doesn't work on IE9 (但它在 IE6、7、8 上确实如此),我自己检查了它 - 在 IE9 上(仅)Invoke 方法失败并返回 DISP_E_EXCEPTION。
所以我仍在寻找更好的解决方案。

已编辑:
这是适用于所有 IE 浏览器的代码:

bool VariantToArray(__in const CComVariant& var, __out vector<CComVariant>& vecVars)
        {
            // convert variant to dispatch object
            CComPtr<IDispatch> 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<nLength ; ++i)
            {
                // get DISPID of item[i] from array object
                wstring strIndex = StringUtils::IntToString(i);
                DISPID dispidIndex = 0;
                LPOLESTR pIndex = reinterpret_cast<LPOLESTR>(const_cast<WCHAR *>(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;
        }

享受 :)

关于javascript - 如何将 JavaScript array() 转换为 ATL/COM 数组?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5014711/

相关文章:

javascript - Web 上的旋转对象

javascript - AngularJS 智能表全局配置实现

javascript - 我可以将 templateUrl 传递给指令吗 - AngularJS

C++ 部分模板特化 :Undeclared identifier error

c++ - 将 QComboBox::currentIndexChanged(int) 连接到 QSignalMapper::map()

c++ - 无权访问模板模板参数

sql - 如何从数组 PostgreSQL 的列中获取唯一值

javascript - 使用 Object.create 的优势

c++ - 将 C 风格数组从 xtensor 移至 `xt::array`

C 程序正在执行一个分支,即使它不应该