Question

I've been looking hard for this but still have not found any solution. I'm using native win32 c++ (no MFC, ATL or .NET)

I'm loading an html document with IHTMLDocument2->write(). I would like to get the event when the page is ready to show, meaning that all images and elements are downloaded and rendered.

Following the embedded browser object from here embedded web control (IWebBrowser2), embedded javascript's onkeydown and onkeyup not firing and from here http://www.codeproject.com/Articles/3365/Embed-an-HTML-control-in-your-own-window-using-pla I managed to get an embedded web browser working fine and loading an html bstr.

I modified the control as shown below. Now I can get the events from the document but never getting DISPID_DOCUMENTCOMPLETE. The only workaround to get this event is when in the html there is an iframe with src attribute:

<html>
  ...
  <body>
    <iframe src="...">...</iframe>
  </body>
</html>

Then the window created by <iframe src="..."> launches the DISPID_DOCUMENTCOMPLETE when the src is ready to show. (It requires to refresh the browser after writting the content)

If the <iframe> has no "src" then the event is fired but the iframe content is never rendered.

In http://msdn.microsoft.com/en-us/library/aa768282.aspx it says that one documentComplete event will be fired for each window in the document, but as I am not using "Navigate" to load the html content and DocumentComplete never gets fired, I suspect that DocumentComplete only gets fired after "Navigate", not when using "write()" neither when using "write() + close()" to load html.

I've also tried to override "its" internet protocol, so when navigating to "its://..." I managed to load the document (idea from here: http://sumatrapdf.googlecode.com/svn/trunk/src/utils/HtmlWindow.cpp). Then I got DISPID_DOCUMENTCOMPLETE for each navigation, but after 10-12 navigations the program chrashes (it released the EventSink object more times than refferenced... weird). After days of trying I concluded that I'm not so experienced to get this working and as it was not a really nice solution, just an ugly workaround, I decided to go back to IHTMLDocument2->write().

I've also tried to attach to DIID_HTMLDocumentEvents2 the get DISPID_HTMLELEMENTEVENTS2_ONREADYSTATECHANGE but no success at all.

Please, any solution?

EmbBrowser.h:

(EmbBrowserEventSink is a simple IDIspatch implementation and IBrowserEventListener is an interface with onDocumentComplete and onClick methods)

    #pragma once

#include <stdio.h>
#include <Windows.h>
#include <string>
#include <Exdisp.h>
#include <comdef.h> // for variant_t
#include <exception>
#include <mshtml.h>    // Defines of stuff like IHTMLDocument2. This is an include file with Visual C 6 and above

#include "EmbBrowserEventSink.h"

//------------------------------------------------------------------------------
class EmbBrowser : public IUnknown, public IOleClientSite, public IOleInPlaceSite, public IStorage{
public:
  EmbBrowser(HWND _mainWindow, IBrowserEventListener *browserEventListener = NULL);
  ~EmbBrowser();

  HRESULT STDMETHODCALLTYPE setEventListener(IBrowserEventListener *browserEventListener) {
    this->mBrowserEventListener = browserEventListener;
    return S_OK;
  };
  HRESULT STDMETHODCALLTYPE hideScrollBars();
  HRESULT STDMETHODCALLTYPE displayHTMLStr(LPCTSTR htmlSource);
  HRESULT STDMETHODCALLTYPE pixelToHiMetric(const RECT& _rc, RECT *_metricRc);
  virtual HRESULT STDMETHODCALLTYPE setRect(const RECT &_rc);
  virtual HRESULT STDMETHODCALLTYPE adjustSize(HWND hWnd);
  virtual HRESULT STDMETHODCALLTYPE navigate(LPCTSTR _url);

  // ----- IUnknown -----

  virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void**ppvObject) override;
  virtual ULONG STDMETHODCALLTYPE AddRef(void) override { return ++m_comRefCount; };
  virtual ULONG STDMETHODCALLTYPE Release( void) override  {
    if (!--m_comRefCount) {
      delete this;
    }
    return m_comRefCount;
  };

  // ---------- IOleWindow ----------

  virtual /* [input_sync] */ HRESULT STDMETHODCALLTYPE GetWindow(/* [out] */ __RPC__deref_out_opt HWND *phwnd) override;
  virtual HRESULT STDMETHODCALLTYPE ContextSensitiveHelp( /* [in] */ BOOL fEnterMode) override { return E_NOTIMPL; };

  // ---------- IOleInPlaceSite ----------

  virtual HRESULT STDMETHODCALLTYPE CanInPlaceActivate(void) override { return S_OK; };
  virtual HRESULT STDMETHODCALLTYPE OnInPlaceActivate(void) override;
  virtual HRESULT STDMETHODCALLTYPE OnUIActivate(void) override { return S_OK; };
  virtual HRESULT STDMETHODCALLTYPE GetWindowContext( 
    /* [out] */ __RPC__deref_out_opt IOleInPlaceFrame **ppFrame,
    /* [out] */ __RPC__deref_out_opt IOleInPlaceUIWindow **ppDoc,
    /* [out] */ __RPC__out LPRECT lprcPosRect,
    /* [out] */ __RPC__out LPRECT lprcClipRect,
    /* [out][in] */ __RPC__inout LPOLEINPLACEFRAMEINFO lpFrameInfo) override;

  virtual HRESULT STDMETHODCALLTYPE Scroll(/* [in] */ SIZE scrollExtant) override { return E_NOTIMPL; };
  virtual HRESULT STDMETHODCALLTYPE OnUIDeactivate(/* [in] */ BOOL fUndoable) override { return S_OK; };
  virtual HWND    STDMETHODCALLTYPE GetControlWindow();
  virtual HRESULT STDMETHODCALLTYPE OnInPlaceDeactivate(void) override;
  virtual HRESULT STDMETHODCALLTYPE DiscardUndoState(void) override { return E_NOTIMPL; };
  virtual HRESULT STDMETHODCALLTYPE DeactivateAndUndo(void) override { return E_NOTIMPL; };
  virtual HRESULT STDMETHODCALLTYPE OnPosRectChange(/* [in] */ __RPC__in LPCRECT lprcPosRect) override { return E_NOTIMPL; };

  // ---------- IOleClientSite ----------

  virtual HRESULT STDMETHODCALLTYPE SaveObject(void) override { return E_NOTIMPL; };
  virtual HRESULT STDMETHODCALLTYPE GetMoniker(
    /* [in] */ DWORD dwAssign,
    /* [in] */ DWORD dwWhichMoniker,
    /* [out] */ __RPC__deref_out_opt IMoniker **ppmk) override
  {
    if((dwAssign == OLEGETMONIKER_ONLYIFTHERE) && (dwWhichMoniker == OLEWHICHMK_CONTAINER)) {
      return E_FAIL;
    }
    return E_NOTIMPL;
  };

  virtual HRESULT STDMETHODCALLTYPE GetContainer(/* [out] */ __RPC__deref_out_opt IOleContainer **ppContainer) override { return E_NOINTERFACE; };
  virtual HRESULT STDMETHODCALLTYPE ShowObject( void) override { return S_OK; };
  virtual HRESULT STDMETHODCALLTYPE OnShowWindow( /* [in] */ BOOL fShow) override { return S_OK; };;
  virtual HRESULT STDMETHODCALLTYPE RequestNewObjectLayout( void) override { return E_NOTIMPL; };

  // ----- IStorage -----

  virtual HRESULT STDMETHODCALLTYPE CreateStream( 
    /* [string][in] */ __RPC__in_string const OLECHAR *pwcsName,
    /* [in] */ DWORD grfMode,
    /* [in] */ DWORD reserved1,
    /* [in] */ DWORD reserved2,
    /* [out] */ __RPC__deref_out_opt IStream **ppstm) override { return E_NOTIMPL; };

  virtual /* [local] */ HRESULT STDMETHODCALLTYPE OpenStream( 
    /* [string][in] */ const OLECHAR *pwcsName,
    /* [unique][in] */ void *reserved1,
    /* [in] */ DWORD grfMode,
    /* [in] */ DWORD reserved2,
    /* [out] */ IStream **ppstm) override { return E_NOTIMPL; };

  virtual HRESULT STDMETHODCALLTYPE CreateStorage( 
    /* [string][in] */ __RPC__in_string const OLECHAR *pwcsName,
    /* [in] */ DWORD grfMode,
    /* [in] */ DWORD reserved1,
    /* [in] */ DWORD reserved2,
    /* [out] */ __RPC__deref_out_opt IStorage **ppstg) override { return E_NOTIMPL; };

  virtual HRESULT STDMETHODCALLTYPE OpenStorage( 
    /* [string][unique][in] */ __RPC__in_opt_string const OLECHAR *pwcsName,
    /* [unique][in] */ __RPC__in_opt IStorage *pstgPriority,
    /* [in] */ DWORD grfMode,
    /* [unique][in] */ __RPC__deref_opt_in_opt SNB snbExclude,
    /* [in] */ DWORD reserved,
    /* [out] */ __RPC__deref_out_opt IStorage **ppstg) override { return E_NOTIMPL; };

  virtual /* [local] */ HRESULT STDMETHODCALLTYPE CopyTo( 
    /* [in] */ DWORD ciidExclude,
    /* [size_is][unique][in] */ const IID *rgiidExclude,
    /* [annotation][unique][in] */ 
    __RPC__in_opt  SNB snbExclude,
    /* [unique][in] */ IStorage *pstgDest) override { return E_NOTIMPL; };

  virtual HRESULT STDMETHODCALLTYPE MoveElementTo( 
    /* [string][in] */ __RPC__in_string const OLECHAR *pwcsName,
    /* [unique][in] */ __RPC__in_opt IStorage *pstgDest,
    /* [string][in] */ __RPC__in_string const OLECHAR *pwcsNewName,
    /* [in] */ DWORD grfFlags) override { return E_NOTIMPL; };

  virtual HRESULT STDMETHODCALLTYPE Commit(/* [in] */ DWORD grfCommitFlags) override { return E_NOTIMPL; };
  virtual HRESULT STDMETHODCALLTYPE Revert(void) override { return E_NOTIMPL; };

  virtual /* [local] */ HRESULT STDMETHODCALLTYPE EnumElements( 
    /* [in] */ DWORD reserved1,
    /* [size_is][unique][in] */ void *reserved2,
    /* [in] */ DWORD reserved3,
    /* [out] */ IEnumSTATSTG **ppenum) override { return E_NOTIMPL; };

  virtual HRESULT STDMETHODCALLTYPE DestroyElement(/* [string][in] */ __RPC__in_string const OLECHAR *pwcsName) override { return E_NOTIMPL; };

  virtual HRESULT STDMETHODCALLTYPE RenameElement( 
    /* [string][in] */ __RPC__in_string const OLECHAR *pwcsOldName,
    /* [string][in] */ __RPC__in_string const OLECHAR *pwcsNewName) override { return E_NOTIMPL; };

  virtual HRESULT STDMETHODCALLTYPE SetElementTimes( 
    /* [string][unique][in] */ __RPC__in_opt_string const OLECHAR *pwcsName,
    /* [unique][in] */ __RPC__in_opt const FILETIME *pctime,
    /* [unique][in] */ __RPC__in_opt const FILETIME *patime,
    /* [unique][in] */ __RPC__in_opt const FILETIME *pmtime) override { return E_NOTIMPL; };

  virtual HRESULT STDMETHODCALLTYPE SetClass(/* [in] */ __RPC__in REFCLSID clsid) override { return S_OK; };

  virtual HRESULT STDMETHODCALLTYPE SetStateBits( 
    /* [in] */ DWORD grfStateBits,
    /* [in] */ DWORD grfMask) override { return E_NOTIMPL; };

  virtual HRESULT STDMETHODCALLTYPE Stat( 
    /* [out] */ __RPC__out STATSTG *pstatstg,
    /* [in] */ DWORD grfStatFlag) override { return E_NOTIMPL; };


protected:
private:
  IOleObject            *m_oleObject;
  LONG                  m_comRefCount;
  HWND                  m_mainWindow;
  RECT                  m_objectRect;
  IWebBrowser2          *m_webBrowser;
  IOleInPlaceObject     *m_oleInPlaceObject;
  HWND                  m_controlWindow;
  DWORD                 mAdviseBrowserEventsCookie;
  IBrowserEventListener *mBrowserEventListener;
  EmbBrowserEventSink   *mEmbBrowserEventSink;

  HRESULT STDMETHODCALLTYPE connectEvents();
  HRESULT STDMETHODCALLTYPE disconnectEvents();
};

EmbBrowser.cpp

#include "StdAfx.h"
#include "EmbBrowser.h"

EmbBrowser::EmbBrowser(HWND _mainWindow, IBrowserEventListener *browserEventListener) : m_mainWindow(_mainWindow),
  mBrowserEventListener(browserEventListener), m_comRefCount(0), mEmbBrowserEventSink(NULL), mAdviseBrowserEventsCookie(0)
{
  ::SetRect(&m_objectRect, -300, -300, 300, 300);

  HRESULT hr = ::OleCreate(CLSID_WebBrowser, IID_IOleObject, OLERENDER_DRAW, 0, this, this, (void**)&m_oleObject);
  if (FAILED(hr)) {
    throw new exception("OleCreate() failed");
  }

  hr = m_oleObject->SetClientSite(this);
  hr = OleSetContainedObject(m_oleObject, TRUE);

  if (FAILED(m_oleObject->DoVerb(OLEIVERB_INPLACEACTIVATE, NULL, this, -1, m_mainWindow, &m_objectRect))) {
    throw new exception("DoVerb(OLEIVERB_INPLACEACTIVATE) failed");
  }

  hr = m_oleObject->QueryInterface(&m_webBrowser);
  if (FAILED(hr)) {
    throw new exception("QueryInterface(IWebBrowser) failed");
  }

  this->navigate(L"about:blank");
}

EmbBrowser::~EmbBrowser() {
  this->m_webBrowser->Release();
  this->m_oleObject->Close(OLECLOSE_NOSAVE);
  this->m_oleObject->Release();
}

HRESULT STDMETHODCALLTYPE EmbBrowser::navigate(LPCTSTR _url) {
  BSTR url;
  url = SysAllocString(_url);
  variant_t flags(0x02u); // navNoHistory;
  HRESULT hr = m_webBrowser->Navigate(url, &flags, NULL, NULL, NULL);
  SysFreeString(url);

  return hr;
}

HRESULT STDMETHODCALLTYPE EmbBrowser::hideScrollBars() {
  HRESULT           hr;
  IDispatch         *pDocDispatch = 0;
  IHTMLDocument2    *pHtmlDocument = 0;
  IHTMLElement      *pBodyElm = 0;
  IHTMLBodyElement  *pBody = 0;
  VARIANT           v;

  hr = m_webBrowser->get_Document(&pDocDispatch);
  if (FAILED(hr) || !pDocDispatch) {
    goto hideScrollBar_clean;
  }

  hr = pDocDispatch->QueryInterface(IID_IHTMLDocument2, (void **) &pHtmlDocument);
  if (FAILED(hr) && !pHtmlDocument) {
    goto hideScrollBar_clean;
  }

  hr = pHtmlDocument->get_body(&pBodyElm);
  if (FAILED(hr) && !pBodyElm) {
    goto hideScrollBar_clean;
  }

  hr = pBodyElm->QueryInterface(IID_IHTMLBodyElement, (void **) &pBody);
  if (FAILED(hr) && !pBody) {
    goto hideScrollBar_clean;
  }

  v.vt = VT_INT;
  v.intVal = 0;

  pBody->put_scroll(L"no");
  pBody->put_leftMargin(v);
  pBody->put_topMargin(v);


hideScrollBar_clean:

  if (pBody) {
    pBody->Release();
  }
  if (pBodyElm) {
    pBodyElm->Release();
  }
  if (pHtmlDocument) {
    pHtmlDocument->Release();
  }
  if (pDocDispatch) {
    pDocDispatch->Release();
  }

  return hr;
}

HRESULT STDMETHODCALLTYPE EmbBrowser::displayHTMLStr(LPCTSTR htmlSource) {
  // This is used by DisplayHTMLStr(). It can be global because we never change it.
  static const SAFEARRAYBOUND ArrayBound = {1, 0};

  HRESULT                   hr;

  IDispatch                 *pDispatch = 0;
  IHTMLDocument2            *pHtmlDoc2 = 0;
  SAFEARRAY                 *sfArray = 0;
  VARIANT                   *pVar = 0;
  BSTR                      bstr = 0;

  hr = m_webBrowser->get_Document(&pDispatch);
  if (FAILED(hr) || !pDispatch) {
    goto displayHTMLStr_clean;
  }

  hr = pDispatch->QueryInterface(IID_IHTMLDocument2, (void **) &pHtmlDoc2);
  if (FAILED(hr) || !pHtmlDoc2) {
    goto displayHTMLStr_clean;
  }

  // Our HTML must be in the form of a BSTR. And it must be passed to write() in an
  // array of "VARIENT" structs. So let's create all that.
  sfArray = SafeArrayCreate(VT_VARIANT, 1, (SAFEARRAYBOUND *) &ArrayBound);
  if (!sfArray) {
    goto displayHTMLStr_clean;
  }

  hr = SafeArrayAccessData(sfArray, (void**) &pVar);
  if (FAILED(hr)) {
    goto displayHTMLStr_clean;
  }

  pVar->vt = VT_BSTR;

#ifndef UNICODE
  {
    wchar_t    *buffer;
    DWORD      size;

    size = MultiByteToWideChar(CP_ACP, 0, htmlSource, -1, 0, 0);
    if (!(buffer = (wchar_t *)GlobalAlloc(GMEM_FIXED, sizeof(wchar_t) * size))) {
      goto displayHTMLStr_clean;
    }
    MultiByteToWideChar(CP_ACP, 0, htmlSource, -1, buffer, size);
    bstr = SysAllocString(buffer);
    GlobalFree(buffer);
  }
#else
  bstr = SysAllocString(htmlSource);
#endif

  if (!bstr) {
    hr = E_OUTOFMEMORY;
    goto displayHTMLStr_clean;
  }

  // Connect HTMLDocumentEvents2 to get onDocumentComplete and onClick events
  this->connectEvents();

  //mEmbBrowserEventSink->setFinishedWriting(false);
  hr = pHtmlDoc2->clear();
  if (FAILED(hr)) {
    goto displayHTMLStr_clean;
  }

  hr = pHtmlDoc2->write(sfArray);
  if (FAILED(hr)) {
    goto displayHTMLStr_clean;
  }

  hr = pHtmlDoc2->close();
  if (FAILED(hr)) {
    goto displayHTMLStr_clean;
  }

  //mEmbBrowserEventSink->setFinishedWriting(true);
  //hr = m_webBrowser->Refresh();
  //if (FAILED(hr)) {
  //  goto displayHTMLStr_clean;
  //}

  //this->mBrowserEventListener->onDocumentComplete(true);


displayHTMLStr_clean:

  // Normally, we'd need to free our BSTR, but SafeArrayDestroy() does it for us
  // SysFreeString(bstr);
  if (bstr) {
    SysFreeString(bstr);
  }
  if (sfArray) {
    // SafeArrayDestroy(sfArray);
    SafeArrayUnaccessData(sfArray);
  }
  if (pHtmlDoc2) {
    pHtmlDoc2->Release();
  }
  if (pDispatch) {
    pDispatch->Release();
  }

  return hr;
}

HRESULT STDMETHODCALLTYPE EmbBrowser::connectEvents() {
  HRESULT                   hr;
  IConnectionPointContainer *pCPC = 0;
  IConnectionPoint          *pCP = 0;
  IUnknown                  *pUnkEventSink = 0;

  this->disconnectEvents();

  this->mEmbBrowserEventSink = new EmbBrowserEventSink(m_webBrowser, this->mBrowserEventListener);
  hr = this->mEmbBrowserEventSink->QueryInterface(IID_IUnknown, (void **) &pUnkEventSink);
  if (FAILED(hr) || !pUnkEventSink) {
    goto connectEvents_clean;
  }

  hr = /*pHtmlDoc2*/m_webBrowser->QueryInterface(IID_IConnectionPointContainer, (void **) &pCPC);
  if (FAILED(hr) || !pCPC) {
    goto connectEvents_clean;
  }

  hr = pCPC->FindConnectionPoint(/*DIID_HTMLDocumentEvents2*/ DIID_DWebBrowserEvents2, &pCP);
  if (FAILED(hr) || !pCP) {
    goto connectEvents_clean;
  }

  hr = pCP->Advise(pUnkEventSink, &mAdviseBrowserEventsCookie);
  if (FAILED(hr)) {
    goto connectEvents_clean;
  }

connectEvents_clean:

  if (pCP) {
    pCP->Release();
  }
  if (pCPC) {
    pCPC->Release();
  }
  if (pUnkEventSink) {
    pUnkEventSink->Release();
  }

  return hr;
}

HRESULT STDMETHODCALLTYPE EmbBrowser::disconnectEvents() {
  HRESULT                   hr;
  IDispatch                 *pDispatch = 0;
  IHTMLDocument2            *pHtmlDoc2 = 0;
  IConnectionPointContainer *pCPC = 0;
  IConnectionPoint          *pCP = 0;

  if (!mAdviseHTMLEventsCookie) {
    hr = S_OK;
    goto disconnectHtmlEvents_clean;
  }

  //hr = m_webBrowser->get_Document(&pDispatch);
  //if (FAILED(hr) || !pDispatch) {
  //  goto disconnectHtmlEvents_clean;
  //}

  //hr = pDispatch->QueryInterface(IID_IHTMLDocument2, (void **) &pHtmlDoc2);
  //if (FAILED(hr) || !pHtmlDoc2) {
  //  goto disconnectHtmlEvents_clean;
  //}

  hr = /*pHtmlDoc2*/this->m_webBrowser->QueryInterface(IID_IConnectionPointContainer, (void **) &pCPC);
  if (FAILED(hr) || !pCPC) {
    goto disconnectHtmlEvents_clean;
  }

  hr = pCPC->FindConnectionPoint(/*DIID_HTMLDocumentEvents2*/ DIID_DWebBrowserEvents2, &pCP);
  if (FAILED(hr) || !pCP) {
    goto disconnectHtmlEvents_clean;
  }

  hr = pCP->Unadvise(mAdviseBrowserEventsCookie);
  if (FAILED(hr)) {
    goto disconnectHtmlEvents_clean;
  }

  mAdviseBrowserEventsCookie= 0;


disconnectHtmlEvents_clean:
  if (pCP) {
    pCP->Release();
  }
  if (pCPC) {
    pCPC->Release();
  }
  if (pHtmlDoc2) {
    pHtmlDoc2->Release();
  }
  if (pDispatch) {
    pDispatch->Release();
  }

  return hr;
}

HRESULT STDMETHODCALLTYPE EmbBrowser::pixelToHiMetric(const RECT& _rc, RECT *_metricRc) {
  static bool s_initialized = false;
  static int s_pixelsPerInchX, s_pixelsPerInchY;

  if (!_metricRc) {
    return E_INVALIDARG;
  }

  if (!s_initialized) {
    HDC hdc = ::GetDC(NULL);
    s_pixelsPerInchX = ::GetDeviceCaps(hdc, LOGPIXELSX);
    s_pixelsPerInchY = ::GetDeviceCaps(hdc, LOGPIXELSY);
    ::ReleaseDC(NULL, hdc);
    s_initialized = true;
  }

  RECT rc;
  _metricRc->left = MulDiv(2540, _rc.left, s_pixelsPerInchX);
  _metricRc->top = MulDiv(2540, _rc.top, s_pixelsPerInchY);
  _metricRc->right = MulDiv(2540, _rc.right, s_pixelsPerInchX);
  _metricRc->bottom = MulDiv(2540, _rc.bottom, s_pixelsPerInchY);

  return S_OK;
}


HRESULT STDMETHODCALLTYPE EmbBrowser::setRect(const RECT &_rc) {
  HRESULT hr = E_FAIL;

  m_objectRect = _rc;

  {
    RECT hiMetricRect;
    hr = pixelToHiMetric(m_objectRect, &hiMetricRect);
    SIZEL sz;
    sz.cx = hiMetricRect.right - hiMetricRect.left;
    sz.cy = hiMetricRect.bottom - hiMetricRect.top;
    m_oleObject->SetExtent(DVASPECT_CONTENT, &sz);
  }

  if (m_oleInPlaceObject != NULL) {
    hr = m_oleInPlaceObject->SetObjectRects(&m_objectRect, &m_objectRect);
  }

  return S_OK;
}

HRESULT STDMETHODCALLTYPE EmbBrowser::adjustSize(HWND hWnd) {
  RECT rc;
  GetWindowRect(hWnd, &rc);
  rc.bottom -= rc.top;
  rc.top    -= rc.top;
  rc.right  -= rc.left;
  rc.left   -= rc.left;

  return setRect(rc);
}

// -----== IUnknown ==----->

HRESULT STDMETHODCALLTYPE EmbBrowser::QueryInterface(REFIID riid, void **ppvObject) {

  if (riid == __uuidof(IUnknown)) {
    (*ppvObject) = static_cast<IUnknown *> (this);

  } else if (riid == __uuidof(IOleClientSite)) {
    (*ppvObject) = static_cast<IOleClientSite *> (this);

  } else if (riid == __uuidof(IOleInPlaceSite)) {
    (*ppvObject) = static_cast<IOleInPlaceSite *> (this);

  } else if(riid == __uuidof(IStorage)) {
    (*ppvObject) = static_cast<IStorage *> (this);

  } else if (riid == __uuidof(IOleWindow)) {
    (*ppvObject) = static_cast<IOleWindow *> (this);

  } else {
    (*ppvObject) = 0;
    return E_NOINTERFACE;
  }

  AddRef(); // implicit AddRef()

  return S_OK;
}

// ----------== IOleWindow ==---------->

HRESULT STDMETHODCALLTYPE EmbBrowser::GetWindow(__RPC__deref_out_opt HWND *phwnd) {
  (*phwnd) = m_mainWindow;

  return S_OK;
}

// ----------== IOleInPlaceSite ==---------->

HRESULT STDMETHODCALLTYPE EmbBrowser::OnInPlaceActivate(void) {
  OleLockRunning(m_oleObject, TRUE, FALSE);
  m_oleObject->QueryInterface(&m_oleInPlaceObject);
  m_oleInPlaceObject->SetObjectRects(&m_objectRect, &m_objectRect);

  return S_OK;
}

HRESULT STDMETHODCALLTYPE EmbBrowser::GetWindowContext(__RPC__deref_out_opt IOleInPlaceFrame **ppFrame,
                                                       __RPC__deref_out_opt IOleInPlaceUIWindow **ppDoc,
                                                       __RPC__out LPRECT lprcPosRect,__RPC__out LPRECT lprcClipRect,
                                                       __RPC__inout LPOLEINPLACEFRAMEINFO lpFrameInfo)
{
  HWND hwnd = m_mainWindow;

  (*ppFrame) = NULL;
  (*ppDoc) = NULL;
  (*lprcPosRect).left   = m_objectRect.left;
  (*lprcPosRect).top    = m_objectRect.top;
  (*lprcPosRect).right  = m_objectRect.right;
  (*lprcPosRect).bottom = m_objectRect.bottom;
  *lprcClipRect = *lprcPosRect;

  lpFrameInfo->fMDIApp = false;
  lpFrameInfo->hwndFrame = hwnd;
  lpFrameInfo->haccel = NULL;
  lpFrameInfo->cAccelEntries = 0;

  return S_OK;
}

HWND STDMETHODCALLTYPE EmbBrowser::GetControlWindow() {
  if(m_controlWindow != NULL) {
    return m_controlWindow;
  }

  if(m_oleInPlaceObject == NULL) {
    return NULL;
  }

  m_oleInPlaceObject->GetWindow(&m_controlWindow);

  return m_controlWindow;
}

HRESULT STDMETHODCALLTYPE EmbBrowser::OnInPlaceDeactivate(void) {
  m_controlWindow = NULL;
  m_oleInPlaceObject = NULL;

  return S_OK;
}
Was it helpful?

Solution

Thanks to Remy, I tried again loading with IPersistStreamInit and now it seems to be working. Here it is the new displayHTMLStr():

HRESULT STDMETHODCALLTYPE EmbBrowser::displayHTMLStr(LPCTSTR htmlSource) {
  HRESULT                   hr;

  IDispatch                 *pDispatch = 0;
  IHTMLDocument2            *pHtmlDoc2 = 0;
  IPersistStreamInit        *pPSI = 0;
  IStream                   *pStream = 0;
  HGLOBAL                   hHTMLContent;

  hr = m_webBrowser->get_Document(&pDispatch);
  if (FAILED(hr) || !pDispatch) {
    goto displayHTMLStr_clean;
  }

  hr = pDispatch->QueryInterface(IID_IHTMLDocument2, (void **) &pHtmlDoc2);
  if (FAILED(hr) || !pHtmlDoc2) {
    goto displayHTMLStr_clean;
  }

  hr = pHtmlDoc2->QueryInterface(IID_IPersistStreamInit, (void **) &pPSI);
  if (FAILED(hr) || !pPSI) {
    goto displayHTMLStr_clean;
  }

  // allocate global memory to copy the HTML content to
  hHTMLContent = ::GlobalAlloc(GPTR, (::_tcslen(htmlSource) + 1) * sizeof(TCHAR));
  if (!hHTMLContent) {
    hr = E_OUTOFMEMORY;
    goto displayHTMLStr_clean;
  }

  ::_tcscpy((TCHAR *) hHTMLContent, htmlSource);

  // create a stream object based on the HTML content
  hr = ::CreateStreamOnHGlobal(hHTMLContent, TRUE, &pStream);
  if (FAILED(hr) || !pStream) {
    goto displayHTMLStr_clean;
  }

  hr = pPSI->InitNew();
  if (FAILED(hr)) {
    goto displayHTMLStr_clean;
  }

  // Connect HTMLDocumentEvents2 to get onDocumentComplete and onClick events
  this->connectEvents();
  hr = pPSI->Load(pStream);

  _tprintf(_T("Written: \n%s\n\n"), htmlSource);


displayHTMLStr_clean:

  if (pStream) {
    pStream->Release();
  }
  if (hHTMLContent) {
    GlobalFree(hHTMLContent);
  }
  if (pPSI) {
    pPSI->Release();
  }
  if (pHtmlDoc2) {
    pHtmlDoc2->Release();
  }
  if (pDispatch) {
    pDispatch->Release();
  }

  return hr;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top