Jisp阵列上的IDispatch :: Invoke _NewEnum在IE9中不起作用

时间:2012-02-24 17:05:27

标签: javascript com mfc internet-explorer-9 atl

我有一个ActiveX组件,它从javascript接收字节数组并处理它。我写了下面的代码,它适用于IE7& 8但是在IE 9中它失败了,而我调用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;


    }

Aprroach 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 个答案:

答案 0 :(得分:2)

我认为你对你的问题有错误的诊断。标题应为:jscript9不支持数组对象的NewEnum。如果有的话,我很惊讶它在以前的版本上为你工作 - 我没有尝试过,但在IE9(jscript9.dll)上,无法使用SAFEARRAY和IEnumVeriant以及任何其他Array构造访问JavaScript数组。 Javascript数组只是常规的IDispatchEx对象。您可以将各个项目作为“0”,“1”和“2”访问。

Eric Lippert的以下帖子解释了JavaScript数组:http://blogs.msdn.com/b/ericlippert/archive/2003/09/22/53061.aspx

在您的C ++代码中,使用指向IDispatch的pDisp指针执行以下操作(第一个元素的伪代码):

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

这是非常JavaScript的东西。 VBScript将传递一个完全不同的构造(可能是SAFEARRAY)。如果您使用pDisp-&gt; GetTypeInfo,您可以准确调查您在pDisp上获得的内容,并使用ITypeInfo :: GetTypeAttr获取有关该类型的信息。 TYPEATTR.cVars返回属性数,GetVarDesc返回有关每个变量的信息。验证没有'Length'或'Count'或_NewEnum变量,而有“0”,“1”,“2”变量可以提取。