我有以下代码(其中windowDisp
是IDispatchEx
代表IE中的文档):
DISPID dispId = 0;
HRESULT res = windowDisp->GetDispID(objectNameStr, fdexNameEnsure, &dispId);
if (FAILED(res))
{
LOG_ERROR("Failed creating " << AnsiConverter(objectName) << " object in "
<< AnsiConverter(url) << ", HResult: " << res);
return false;
}
if (dispId == DISPID_UNKNOWN)
{
LOG_ERROR("Creating " << AnsiConverter(objectName) << " object in "
<< AnsiConverter(url) << " resulted in DISPID_UNKNOWN");
}
// Validate creating property
DISPID testDispId = 0;
res = windowDisp->GetDispID(objectNameStr, 0, &testDispId);
if (FAILED(res) || dispId != testDispId)
{
LOG_ERROR("Failed validating " << AnsiConverter(objectName) << " object in "
<< AnsiConverter(url) << ", HResult: " << res);
if (res == DISP_E_UNKNOWNNAME)
{
std::string all = enumerateDispIds(windowDisp);
LOG_ERROR("Available objects are" << all);
}
return false;
}
并且(从https://msdn.microsoft.com/en-us/library/tt99ahf2(v=vs.94).aspx修改):
static std::string enumerateDispIds(const CComQIPtr<IDispatchEx>& windowDisp)
{
HRESULT hr;
BSTR bstrName;
DISPID dispid;
std::stringstream ss;
hr = windowDisp->GetNextDispID(fdexEnumAll, DISPID_STARTENUM, &dispid);
while (hr == S_OK)
{
hr = windowDisp->GetMemberName(dispid, &bstrName);
ss << "\t" << dispid << ": " << (hr == S_OK ? AnsiConverter(bstrName) : "COULD NOT GET NAME") << std::endl;
SysFreeString(bstrName);
hr = windowDisp->GetNextDispID(fdexEnumAll, dispid, &dispid);
}
return ss.str();
}
我的问题是第一次调用GetDispID
会返回S_OK
和一个有效的dispId,据我所知,这意味着该成员之前已经创建过,或者是在此期间创建的调用(感谢fdexNameEnsure
参数),但第二次调用GetDispID
应该验证成员确实存在,但DISP_E_UNKNOWNNAME
失败。当我查看日志时,我会看到枚举中的所有成员,而这些成员都不是我试图创建的。因此,GetDispID
似乎会返回S_OK
,但并不会真正成功。
我在Windows 10 x64和IE 11上。
我问的原因是我们在测试环境(Windows 7版本7601 SP1 x64,IE 11.0.9600.18347)中使用以下调用堆栈在IE中获取访问冲突(底部3帧是我们然后我们进入IE代码):
jscript9!Js::SimpleDictionaryTypeHandlerBase<unsigned short,Js::PropertyRecord const * __ptr64,0>::HasProperty+0xb0
jscript9!Js::GlobalObject::SetExistingProperty+0x57
jscript9!Js::GlobalObject::SetProperty+0x4f
jscript9!Js::DefaultScriptOperations::DefaultOperationsWrapper<<lambda_0739649a84a512e5527a10b6eeb626fd> >+0x1b6
jscript9!Js::DefaultScriptOperations::SetProperty+0x7b
mshtml!CWindowTypeOperations::SetProperty+0x70
jscript9!Js::CustomExternalObject::SetPropertyImpl<0>+0x133
jscript9!Js::JavascriptExternalOperators::SetProperty+0xd10e6
jscript9!ScriptSite::ExternalSetProperty+0x6f
jscript9!JavascriptDispatch::InvokeOnMember+0x1fa
jscript9!JavascriptDispatch::InvokeEx+0x28e
mshtml!CBase::varInvokeEx+0xbd
Hook64!createHookObject+0x599
Hook64!InjectScript+0x402
Hook64!CHtmlInterceptor::Invoke+0x5bb
获得dispId
后,我们致电InvokeEx
:
windowDisp->InvokeEx(dispId,
LOCALE_USER_DEFAULT,
DISPATCH_PROPERTYPUT,
¶ms,
NULL, NULL, NULL);
这会导致访问冲突。所以我们认为可能没有创建对象......