I have written an implementation of IDocHostUIHandler in order to provide an external object to JavaScript an embedded IE11 control. One class provides implementations of IUnknown, IDispatch and IDocHostUIHandler. The IDispatch interface is returned to GetExternal as the external object. All calls to IDocHostUIHandler except GetExternal call into the original handler.
For example HideUI is implemented as:
HRESULT STDMETHODCALLTYPE mtQtWebBrowserDocHandler::HideUI(void)
{
qDebug("Calling HideUI");
if(m_defaultDocHostUIHandler)
{
HRESULT hr = m_defaultDocHostUIHandler->HideUI();
qDebug("Called HideUI");
return hr;
}
return E_NOTIMPL;
}
The same pattern is used for all of the other methods except GetExternal which is:
HRESULT STDMETHODCALLTYPE mtQtWebBrowserDocHandler::GetExternal(IDispatch **ppDispatch)
{
qDebug("Calling GetExternal");
*ppDispatch = (IDispatch*)this;
return S_OK;
}
In JavaScript I execute the following:
var r1 = window.external.Test1();
This results in the following debug output tail:
'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
The final return from HideUI causes an INT 29h error with ecx = FAST_FAIL_INCORRECT_STACK. The expected stack is 0x18D9C4 and the actual stack is 0x18D9A4, a discrepancy of 0x20.
I am completely mystified. The other calls to my interface work correctly and it doesn't make any difference if I just return E_NOTIMPL from my implementation of HideUI. What could possibly be unbalancing the stack?
The answer seems to be that I was using ICustomDoc on the browser document when mshtml was being hosted by the WebBrowser control. This is apparently not a good idea! Instead you should use the existing site provided by the WebBrowser control. I found an example of the correct way to implement IDocHostUI here https://github.com/FastSpring/FsprgEmbeddedStoreWinMFC and it was extremely helpful.