mshtml 在调用 HideUI 后失败并显示 FAST_FAIL_INCORRECT_STACK
mshtml fails with FAST_FAIL_INCORRECT_STACK after calling HideUI
我编写了 IDocHostUIHandler 的实现,以便为 JavaScript 嵌入式 IE11 控件提供外部对象。一个 class 提供了 IUnknown、IDispatch 和 IDocHostUIHandler 的实现。 IDispatch 接口作为外部对象被 returned 到 GetExternal。
除了 GetExternal 调用原始处理程序外,对 IDocHostUIHandler 的所有调用。
例如 HideUI 实现为:
HRESULT STDMETHODCALLTYPE mtQtWebBrowserDocHandler::HideUI(void)
{
qDebug("Calling HideUI");
if(m_defaultDocHostUIHandler)
{
HRESULT hr = m_defaultDocHostUIHandler->HideUI();
qDebug("Called HideUI");
return hr;
}
return E_NOTIMPL;
}
除 GetExternal 之外的所有其他方法都使用相同的模式,即:
HRESULT STDMETHODCALLTYPE mtQtWebBrowserDocHandler::GetExternal(IDispatch **ppDispatch)
{
qDebug("Calling GetExternal");
*ppDispatch = (IDispatch*)this;
return S_OK;
}
在JavaScript我执行以下:
var r1 = window.external.Test1();
这导致以下调试输出尾部:
'2016-10-10 11:09:19' DEBUG Calling GetHostInfo
'2016-10-10 11:09:19' DEBUG Called GetHostInfo
'2016-10-10 11:09:19' DEBUG mtQtWebBrowserDocHandler Release (ref now = 2)
'2016-10-10 11:09:19' DEBUG mtQtWebBrowserDocHandler AddRef (ref now = 3)
'2016-10-10 11:09:19' DEBUG Calling GetHostInfo
'2016-10-10 11:09:19' DEBUG Called GetHostInfo
'2016-10-10 11:09:19' DEBUG mtQtWebBrowserDocHandler Release (ref now = 2)
'2016-10-10 11:09:19' DEBUG Calling GetExternal
'2016-10-10 11:09:21' DEBUG mtQtWebBrowserDocHandler - IDispatch requested
'2016-10-10 11:09:21' DEBUG mtQtWebBrowserDocHandler AddRef (ref now = 3)
'2016-10-10 11:09:21' DEBUG mtQtWebBrowserDocHandler Release (ref now = 2)
'2016-10-10 11:09:21' DEBUG Calling ShowUI
'2016-10-10 11:09:21' DEBUG Called ShowUI
'2016-10-10 11:09:21' DEBUG Calling HideUI
'2016-10-10 11:09:21' DEBUG Called HideUI
来自 HideUI 的最终 return 导致 ECx = FAST_FAIL_INCORRECT_STACK 的 INT 29h 错误。预期堆栈为0x18D9C4,实际堆栈为0x18D9A4,相差0x20.
我完全懵了。对我的接口的其他调用工作正常,如果我只是 return E_NOTIMPL 从我的 HideUI 实现中,它没有任何区别。什么可能导致堆栈失衡?
在 GetExternal
函数中,您返回一个接口指针而不增加引用计数,这将导致稍后引用计数不匹配。更好的实现方式是:
HRESULT STDMETHODCALLTYPE mtQtWebBrowserDocHandler::GetExternal(IDispatch **ppDispatch)
{
qDebug("Calling GetExternal");
*ppDispatch = (IDispatch*)this;
this->AddRef();
return S_OK;
}
或在其中使用 QueryInterface
。如果这是 ATL,InternalQueryInterface
。我怀疑这是导致错误的原因,因为您引用了可能由于 Release
次调用多于 AddRef
次调用而被破坏的对象。
答案似乎是,当 mshtml 由 WebBrowser 控件托管时,我在浏览器文档上使用了 ICustomDoc。这显然不是一个好主意!相反,您应该使用 WebBrowser 控件提供的现有站点。我在此处 https://github.com/FastSpring/FsprgEmbeddedStoreWinMFC 找到了实现 IDocHostUI 的正确方法示例,它非常有帮助。
我编写了 IDocHostUIHandler 的实现,以便为 JavaScript 嵌入式 IE11 控件提供外部对象。一个 class 提供了 IUnknown、IDispatch 和 IDocHostUIHandler 的实现。 IDispatch 接口作为外部对象被 returned 到 GetExternal。 除了 GetExternal 调用原始处理程序外,对 IDocHostUIHandler 的所有调用。
例如 HideUI 实现为:
HRESULT STDMETHODCALLTYPE mtQtWebBrowserDocHandler::HideUI(void)
{
qDebug("Calling HideUI");
if(m_defaultDocHostUIHandler)
{
HRESULT hr = m_defaultDocHostUIHandler->HideUI();
qDebug("Called HideUI");
return hr;
}
return E_NOTIMPL;
}
除 GetExternal 之外的所有其他方法都使用相同的模式,即:
HRESULT STDMETHODCALLTYPE mtQtWebBrowserDocHandler::GetExternal(IDispatch **ppDispatch)
{
qDebug("Calling GetExternal");
*ppDispatch = (IDispatch*)this;
return S_OK;
}
在JavaScript我执行以下:
var r1 = window.external.Test1();
这导致以下调试输出尾部:
'2016-10-10 11:09:19' DEBUG Calling GetHostInfo
'2016-10-10 11:09:19' DEBUG Called GetHostInfo
'2016-10-10 11:09:19' DEBUG mtQtWebBrowserDocHandler Release (ref now = 2)
'2016-10-10 11:09:19' DEBUG mtQtWebBrowserDocHandler AddRef (ref now = 3)
'2016-10-10 11:09:19' DEBUG Calling GetHostInfo
'2016-10-10 11:09:19' DEBUG Called GetHostInfo
'2016-10-10 11:09:19' DEBUG mtQtWebBrowserDocHandler Release (ref now = 2)
'2016-10-10 11:09:19' DEBUG Calling GetExternal
'2016-10-10 11:09:21' DEBUG mtQtWebBrowserDocHandler - IDispatch requested
'2016-10-10 11:09:21' DEBUG mtQtWebBrowserDocHandler AddRef (ref now = 3)
'2016-10-10 11:09:21' DEBUG mtQtWebBrowserDocHandler Release (ref now = 2)
'2016-10-10 11:09:21' DEBUG Calling ShowUI
'2016-10-10 11:09:21' DEBUG Called ShowUI
'2016-10-10 11:09:21' DEBUG Calling HideUI
'2016-10-10 11:09:21' DEBUG Called HideUI
来自 HideUI 的最终 return 导致 ECx = FAST_FAIL_INCORRECT_STACK 的 INT 29h 错误。预期堆栈为0x18D9C4,实际堆栈为0x18D9A4,相差0x20.
我完全懵了。对我的接口的其他调用工作正常,如果我只是 return E_NOTIMPL 从我的 HideUI 实现中,它没有任何区别。什么可能导致堆栈失衡?
在 GetExternal
函数中,您返回一个接口指针而不增加引用计数,这将导致稍后引用计数不匹配。更好的实现方式是:
HRESULT STDMETHODCALLTYPE mtQtWebBrowserDocHandler::GetExternal(IDispatch **ppDispatch)
{
qDebug("Calling GetExternal");
*ppDispatch = (IDispatch*)this;
this->AddRef();
return S_OK;
}
或在其中使用 QueryInterface
。如果这是 ATL,InternalQueryInterface
。我怀疑这是导致错误的原因,因为您引用了可能由于 Release
次调用多于 AddRef
次调用而被破坏的对象。
答案似乎是,当 mshtml 由 WebBrowser 控件托管时,我在浏览器文档上使用了 ICustomDoc。这显然不是一个好主意!相反,您应该使用 WebBrowser 控件提供的现有站点。我在此处 https://github.com/FastSpring/FsprgEmbeddedStoreWinMFC 找到了实现 IDocHostUI 的正确方法示例,它非常有帮助。