Я написал реализацию IDocHostUIHandler для обеспечения внешнего объекта JavaScript встроенным элементом управления IE11. Один класс предоставляет реализации IUnknown, IDispatch и IDocHostUIHandler. Интерфейс IDispatch возвращается в GetExternal в качестве внешнего объекта.
Все вызовы IDocHostUIHandler, кроме вызова GetExternal в исходный обработчик.
Например 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 вызывает ошибку INT 29h с ecx = FAST_FAIL_INCORRECT_STACK. Ожидаемый стек 0x18D9C4, а фактический стек 0x18D9A4, расхождение 0x20.
Я полностью озадачен. Другие вызовы моего интерфейса работают правильно, и не имеет никакого значения, если я просто верну 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
звонки.
Похоже, ответ заключается в том, что я использовал ICustomDoc в документе браузера, когда mshtml размещался в элементе управления WebBrowser. Это, видимо, не очень хорошая идея! Вместо этого вы должны использовать существующий сайт, предоставленный элементом управления WebBrowser. Я нашел пример правильного способа реализации IDocHostUI здесь https://github.com/FastSpring/FsprgEmbeddedStoreWinMFC и это было чрезвычайно полезно.