2

I have written a C++ class that encapsulates a web browser (inspired by this). One of the class methods takes HTML code as a string and renders it in the browser. The browser's rendering is asynchronous, and in some situations it is necessary to wait until document loading is complete before proceeding. I am uncertain of whether I am doing this correctly.

What I do is open a new document, call IHTMLDocument2::put_onreadystatechange (passing an instance of an EventSink class that I implemented), and call IHTMLDocument2::write to render the desired HTML. This is all done in the main thread.

The main thread then continues with other things. After a while, when the ready state changes, the browser calls EventSink::Invoke. There, I call IHTMLDocument2::get_readyState and check whether it equals complete. This also happens in the main thread (called by COM via the client stub, if my understandung is correct).

The problem is that although I detect when document loading is complete, the main thread has been doing other things in the mean time, possibly accessing the HTML DOM. So I would like to wait for document completion immediately after calling IHTMLDocument2::write. How does one achieve this? I can't set an event semaphore in the event sink and wait for it, because both pieces of code are executed by the main thread. So should I really be using a worker thread here? I'm somewhat confused about which thread would do what. E.g. the thread invoked by the COM client stub would set the event semaphore when loading is complete, but which thread is that - always the main thread, or the thread that created the COM object? Any help is appreciated.

Dabbler
  • 9,733
  • 5
  • 41
  • 64
  • 1
    Why don't you just return after calling `IHTMLDocument2::write` and move all the remaining logic accessing DOM into event sink handler (when the document is ready)? – Alex Skalozub Jan 04 '15 at 02:02
  • Alex: The main thread continues with the Windows message loop (where the user could trigger many different actions), so I think it would be easiest to just wait, if possible. – Dabbler Jan 04 '15 at 11:36
  • Well, I'd better just disable UI parts which may affect web browser while it is not ready. But you may try to wait for event while processing window messages: `while (WAIT_TIMEOUT == WaitForSingleObject(hEvent, 50)) { DoEvents(); }` (http://stackoverflow.com/questions/1415095/doevents-equivalent-for-c), and then `SetEvent(hEvent);` in event sink. – Alex Skalozub Jan 04 '15 at 20:23
  • 1
    If you are going to use such a loop, then at least use `MsgWaitForMultipleObjects()` instead, and call `DoEvents()` only when it says there are messages waiting to be processed. You can also forgo the eventsink altogether and just read the [`IWebBrowser2.ReadyState`](http://msdn.microsoft.com/en-us/library/aa752141.aspx) property in the loop. – Remy Lebeau Jan 04 '15 at 21:12
  • Don't actively wait, the WebBrowser component requires that messages be processed. Instead, disable the WebBrowser component and all components that interact with it until you have a complete document, which will avoid user interaction while still processing messages. – acelent Jan 05 '15 at 10:07
  • 1
    @AlexSkalozub Of course, if you run a modal message loop, you would have all the same problems that you would if you return to the main message loop - user actions would be accepted and processed. So you might as well just do the right thing from the start - disable whatever UI elements you don't want to be active while the document is not ready, return to the main message pump, and finally in response to `DocumentComplete` event re-enable UI and continue your processing. – Igor Tandetnik Jan 05 '15 at 15:27
  • 1
    `WebBrowser` is an apartment-threaded object. All its processing happens on the thread (necessarily belonging to a single-threaded apartment) that created it (usually, the main UI thread), and that thread (like any thread that has joined STA) is required to pump window messages in a timely manner. You can't turn asynchronous operations into blocking ones; I suggest you concentrate your efforts on dealing with this "not-ready" state correctly in your UI. – Igor Tandetnik Jan 05 '15 at 15:34
  • Igor: Sounds knowledgeable; I'll meditate over it ;-) – Dabbler Jan 05 '15 at 18:03

0 Answers0