Retrieve javascript array object with C++ using DISPID_NEWENUM fails on IE9
following a similar question i answered some time ago, i found out that when trying to enumerate the object, using IDispatch::Invoke(DISPID_NEWENUM,...)
fails开发者_运维百科 with DISP_E_EXCEPTION
on IE9.
IDispatch
and IDispatchEx
, on any javascript array.
needless to say that the code works great on IE6-IE8, and fails only on IE9.
The same question also appears in the MSDN dev forums with no luck so far.
Here's a code snippet to demonstrate what I tried to do. notice that pDispatch
is the javascript's array variant.
// 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 - retry with IDispatchEX
if (FAILED(hr))
{
CComPtr<IDispatchEx> pDispatchEx;
pDispatchEx = pDispatch; // Implied query interface
hr = pDispatchEx->InvokeEx(DISPID_NEWENUM, LOCALE_USER_DEFAULT, DISPATCH_METHOD | DISPATCH_PROPERTYGET, &dispparamsNoArgs, &varResult, &excepInfo, NULL);
if (FAILED(hr))
return false;
}
Does anyone have any idea why this code always fails (IDispatch and IDispatchEx) with HRESULT of DISP_E_EXCEPTION specifically on IE9?
Thanks.
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;
}
IEnumVARIANT may work. Although when I tried it IEnumVARIANT::Next always was returning E_FAIL, the element was fetched correctly. Didn't have time or need to get to the bottom of this.
It worked for me, but if it didn't I was intended to use IDispatchEx: when enumerated members of array objects passed by IE they all had "0", "1" etc.., not "length" method though, must be in it's typeinfo, haven't checked. I think you get the idea.
Sorry can't post pseudo code this site won't allow me without following some special formatting rules
hth
精彩评论