Jeeva
Jeeva

Reputation: 4663

IDispatch::Invoke _NewEnum on JScript Array not working in IE9

I have an ActiveX component which receives byte array from javascript and process it. I wrote the following code and it worked for IE7 & 8 but in IE 9 it is failing while i call IDispatch::Invoke please help me to resolve it

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();


        }

The java script code

<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>

The issue is fixed with the below code Fixed Code

    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;
    }

Upvotes: 1

Views: 1446

Answers (1)

Uri London
Uri London

Reputation: 10797

I think you have the wrong diagnostic about your problem. The title should be: jscript9 doesn't support NewEnum for array objects. If anything, I'm surprised it was working for you on previous version - I didn't try it, but on IE9 (jscript9.dll) JavaScript arrays cannot be accessed with neither SAFEARRAY nor with IEnumVeriant and any other Array construct. Javascript array are nothing but regular IDispatchEx objects. You can access the individual items as "0", "1" and "2".

The following post from Eric Lippert explains JavaScript arrays: http://blogs.msdn.com/b/ericlippert/archive/2003/09/22/53061.aspx

In your C++ code, with your pDisp pointer to IDispatch do the following (pseudo code for first element):

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

This is very JavaScript'y thing. VBScript will pass a completely different construct (probably SAFEARRAY). You can investigate exactly what you are getting at pDisp, if you pDisp->GetTypeInfo, and use the ITypeInfo::GetTypeAttr to get information about the type. TYPEATTR.cVars returns the number of properties, and GetVarDesc returns information about each variable. Verify there are no 'Length' or 'Count' or _NewEnum variables, while there are "0", "1", "2" variables which you can extract.

Upvotes: 2

Related Questions