Reputation: 4663
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(¶ms, 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,¶ms, &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, ¶ms, &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
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