IDispatch :: Invoke _NewEnum на массиве JScript не работает в IE9 - PullRequest
1 голос
/ 24 февраля 2012

У меня есть компонент ActiveX, который получает байтовый массив из JavaScript и обрабатывает его. Я написал следующий код, и он работал для IE7 и 8, но в IE9 он не работает, пока я вызываю IDispatch :: Invoke, пожалуйста, помогите мне решить его

if(pszBufData->vt == VT_DISPATCH)
        {       
            BYTE * pData = new BYTE[dwSize];

            IDispatch *pDisp = pszBufData->pdispVal;
            pDisp->AddRef();

            DISPPARAMS dispparamsNoArgs = { NULL, NULL, 0, 0 };

            VARIANT var;
            VariantInit(&var);

            HRESULT hr = pDisp->Invoke(DISPID_NEWENUM, IID_NULL, GetUserDefaultLCID(), DISPATCH_PROPERTYGET, &dispparamsNoArgs, &var, NULL, NULL);


            int i=0;
            if (SUCCEEDED(hr)) 
            {

             if (var.vt == VT_UNKNOWN) 
             {
                 IEnumVARIANT *pEnum = NULL;
                 if SUCCEEDED(var.punkVal->QueryInterface(IID_IEnumVARIANT, (void**) &pEnum)) 
                 {
                     VARIANT item;
                     VariantInit(&item);

                     pEnum->Reset();
                     while ( (pEnum->Next(1, &item, NULL) && S_FALSE) != S_FALSE) 
                     {                   
                         if (item.vt == VT_I4) 
                         {  
                             //AfxMessageBox(_T("SendData"));
                             pData[i] = item.cVal;
                             i++;
                         }
                         VariantClear(&item);
                     }
                     pEnum->Release();
                 }
                   var.punkVal->Release();
             }
            }

            /*VariantClear(&var);*/
            pDisp->Release();


        }

Код Java-скрипта

<HTML>
<HEAD>
    <SCRIPT LANGUAGE="JavaScript" FOR="window" EVENT="onLoad()">
<!--

var arr = new Array(0x1, 0xA,0x20)

//CSDS_Communication1.ConfigCon("COM1",9600)

CSDS_Communication1.SendData("COM1",arr,3)


-->
    </SCRIPT>
<TITLE>New Page</TITLE>
</HEAD>
<BODY>
    <OBJECT ID="CSDS_Communication1" WIDTH=100 HEIGHT=51
     CLASSID="CLSID:73D79990-090E-48CB-8857-E6BF50F42E63">
        <PARAM NAME="_Version" VALUE="65536">
        <PARAM NAME="_ExtentX" VALUE="2646">
        <PARAM NAME="_ExtentY" VALUE="1323">
        <PARAM NAME="_StockProps" VALUE="0">
    </OBJECT>
</BODY>
</HTML>

Проблема устранена с помощью приведенного ниже кода Фиксированный код

    BYTE * pData = new BYTE[dwSize];

    /* retrieving IDispatch */
    IDispatch *disp = pszBufData->pdispVal;
    if (pszBufData->vt & VT_BYREF)
        disp = *(pszBufData->ppdispVal);

    /* getting array's length */
    DISPPARAMS params;
    FillMemory(&params, sizeof(DISPPARAMS), 0);
    VARIANT res;

    DISPID dl = 0;
    LPOLESTR ln = L"length";
    HRESULT hr = disp->GetIDsOfNames(IID_NULL, &ln, 1, LOCALE_USER_DEFAULT, &dl);
    if (FAILED(hr))
        return false;

    // get the number of elements using the DISPID of length parameter

    hr =disp->Invoke(dl, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET,&params, &res, NULL, NULL);
    if (FAILED(hr))
        return false;


    VARIANT len1;
    VariantInit(&len1);

    VariantChangeType(&len1, &res, 0, VT_I4);

    LONG len = len1.lVal;

    /* summing elements */

    for (int i = 0; i < len; i++)
    {
        std::wstring strIndex;// = StringUtils::IntToString(i);

        wchar_t buf[8];
        _itow(i,buf,10);
        strIndex.append(buf);

        DISPID dispid;

        LPOLESTR pIndex = reinterpret_cast<LPOLESTR>(const_cast<WCHAR *>(strIndex.data()));


        hr = disp->GetIDsOfNames( IID_NULL, &pIndex, 1, LOCALE_USER_DEFAULT, &dispid );
         if (FAILED(hr))
             continue;


        /*std::stringstream ss;
        ss << ind =" CComBSTR(ss.str().c_str());">GetIDsOfNames(IID_NULL, &ind, 1, LOCALE_USER_DEFAULT, &dispid));*/
        hr = disp->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET, &params, &res, NULL, NULL);
        if (FAILED(hr))
             continue;

        VARIANT val1;
        VariantInit(&val1);

        VariantChangeType(&val1, &res, 0, VT_I4);

        pData[i] = val1.lVal;


    }

апрель 2:

IDispatch *disp = pszBufData->pdispVal;
    if (pszBufData->vt & VT_BYREF)
        disp = *(pszBufData->ppdispVal);

    // Get IDispatchEx on input IDispatch
    CComQIPtr<IDispatchEx> pdispexArray(disp);
    if ( ! pdispexArray )
        return E_NOINTERFACE;

    // Get array length DISPID
    DISPID dispidLength;
    CComBSTR bstrLength(L"length");
    HRESULT hr = pdispexArray->GetDispID(bstrLength, fdexNameCaseSensitive, &dispidLength);
    if (FAILED(hr))
        return false;

     // Get length value using InvokeEx()
    CComVariant varLength;
    DISPPARAMS dispParamsNoArgs = {0};
    hr = pdispexArray->InvokeEx(dispidLength, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET, &dispParamsNoArgs, &varLength, 
        NULL, NULL);
    if (FAILED(hr))
        return hr;

    ATLASSERT(varLength.vt == VT_I4);
    const int count = varLength.intVal;

    BYTE * pData = new BYTE[count];

    // For each element in source array:
    for (int i = 0; i < count; i++)
    {
        CString strIndex;
        strIndex.Format(L"%d", i);

        // Convert to BSTR, as GetDispID() wants BSTR's
        CComBSTR bstrIndex(strIndex);
        DISPID dispidIndex;
        hr = pdispexArray->GetDispID(bstrIndex, fdexNameCaseSensitive, &dispidIndex);
        if (FAILED(hr))
            break;

        // Get array item value using InvokeEx()
        CComVariant varItem;
        hr = pdispexArray->InvokeEx(dispidIndex, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET, &dispParamsNoArgs, &varItem, 
            NULL, NULL);
        if (FAILED(hr))
            break;

        ATLASSERT(varItem.vt == VT_I4);

        pData[i] = varItem.intVal;
    }

1 Ответ

2 голосов
/ 25 февраля 2012

Я думаю, у вас неправильная диагностика вашей проблемы.Заголовок должен быть следующим: jscript9 не поддерживает NewEnum для объектов массива.Во всяком случае, я удивлен, что это работало для вас в предыдущей версии - я не пробовал, но в IE9 (jscript9.dll) массивы JavaScript не могут быть доступны ни с SAFEARRAY, ни с IEnumVeriant, ни с любой другой конструкцией Array.Массив Javascript - это не что иное, как обычные объекты IDispatchEx.Вы можете получить доступ к отдельным элементам как «0», «1» и «2».

Следующий пост Эрика Липперта объясняет массивы JavaScript: http://blogs.msdn.com/b/ericlippert/archive/2003/09/22/53061.aspx

В вашем коде C ++, сВаш указатель pDisp на IDispatch делает следующее (псевдокод для первого элемента):

DISPID dispid;
wchar_t name[] = L"0";
pDisp->GetIDsOfNames( IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid );
pDisp->Invoke( dispid, ... );

Это очень JavaScript'ы.VBScript передаст совершенно другую конструкцию (возможно, SAFEARRAY).Вы можете точно узнать, что вы получаете в pDisp, если вы pDisp-> GetTypeInfo, и использовать ITypeInfo :: GetTypeAttr для получения информации о типе.TYPEATTR.cVars возвращает количество свойств, а GetVarDesc возвращает информацию о каждой переменной.Убедитесь, что нет переменных «Length», «Count» или «_NewEnum», а есть переменные «0», «1», «2», которые можно извлечь.

...