How to Cleanly Destroy WebBrowser Control
Asked Answered
S

3

5

I am using ATL in VisualC++10 to host browser control. My code is similar to this example: http://msdn.microsoft.com/en-us/library/9d0714y1(v=vs.80).aspx

Difference is I have main window and then child window hosts the browser control. After 2 minutes i have to close the browser completely kill the browser activeX but this child window should be alive and do something else. But somehow this browser control still stays there, i can either see scrollbars or something..

I have also tried by creating child window to an existing child window, and at the time of closing browser I then destroy this child of a child - but still it does not work!

This is how I am closing:

CLOSE()
{
    m_spIWebBrowser2->Navigate(bstrURL, &vEmpty, &vEmpty, &vEmpty, &vEmpty);
    m_spIWebBrowser2->Stop();
    m_spIWebBrowser2->put_Visible(VARIANT_FALSE);
    m_spIWebBrowser2->Quit();
    DestroyWindow(m_wndChild.m_hWnd);
}

Thanks!

Shippen answered 25/11, 2011 at 20:27 Comment(7)
I remember a problem with closing webbrowser control where the cause was a "local" COM initialization/deinitialization. To support the asynchronous nature of the beast, needs call to CoInitialize in main. But presumably you have that already?Widespread
Yeah those stuff covered up.. We are also using IE controls on Dialogboxes as well - those are working fine.Shippen
I created IE contol on mainwindow via main-thread then main spawns a new thread, from there I am calling navigate() and it shows the web page, after a minute I call this above mentioned close() function from the child thread, browser control disappears but it is still there cause sometimes IEControl scrollbars are visible and iexplore.exe (out-of) process is also running..Shippen
Lifetime of the process is controlled by reference counting. You are not destroying your smart pointer.Conveyancing
Thanks but: IWebBrowser2 *iw; g_spWebBrowser2->QueryInterface(&iw); ULONG ul = iw->Release(); AtlAxWinTerm(); Still - it is hanging around.Shippen
Lets keep this as reference point: msdn.microsoft.com/en-us/library/9d0714y1(v=vs.80).aspx -- I am using USE_METHOD 7 or 8 - Difference is I want to terminate the control but not my main app as in sample.Shippen
If I host the control in a window and then later on destroy the window then IEControl is getting cleaned up - but not 100% as "Internet Explorer_Hidden" is still lying around. While if i put the IE as a ActiveX resource on Dialogbox (CAxDialogImpl) then destroying the dialogbox is doing the cleanup somehow..Shippen
C
12

I had many problems with "access violation" when closing webbrowser control, these are the steps that worked for me:

  1. Unadvise any previously advised events (DWebBrowserEvents2 in my case).
  2. If you've attached click events unattach them like this: _variant_t v; v.vt = VT_DISPATCH; v.pdispVal = 0; IHTMLDocument2->put_onclick(v);
  3. IWebBrowser2->Stop()
  4. IWebBrowser2->ExecWB(OLECMDID_CLOSE, OLECMDEXECOPT_DONTPROMPTUSER, 0, 0) - when closing browser window through window.external.CloseWindow() I had unhandled exceptions and OLECMDID_CLOSE fixed it.
  5. IWebBrowser2->put_Visible(VARIANT_FALSE)
  6. IWebBrowser2->Release()
  7. IOleInPlaceObject->InPlaceDeactivate()
  8. IOleInPlaceObject->Release()
  9. IOleObject->DoVerb(OLEIVERB_HIDE, NULL, IOleClientSite, 0, windowHandle_, NULL)
  10. IOleObject->Close(OLECLOSE_NOSAVE)
  11. OleSetContainedObject(IOleObject, FALSE)
  12. IOleObject->SetClientSite(NULL)
  13. CoDisconnectObject(IOleObject, 0)
  14. IOleObject->Release()

IWebBrowser2->Quit() should not be called for WebBrowser control (CLSID_WebBrowser), it is intended only for Internet Explorer object (CLSID_InternetExplorer).

Why must it be so hard?

Crumpton answered 1/2, 2013 at 18:20 Comment(4)
Voted a while ago but need to say this: This post is GOLD. Helped me crash-proof the embed browser after multiple open/close.Offcolor
Shouldn't (5) be before (3)? (5) prevents any new input from user. (3) stops any ongoing browser activity. Consider user may cause the browser to do something again between (3) and (5), e.g. by clicking somewhere in the browser window. Looks to me as a potential race condition.Diencephalon
@mitty Calls (3) and (4) should execute immediately and I think they are executed on the main UI thread. However I'm no IE expert and it shouldn't hurt to change the sequence of calls as you have suggested. I'm not editing my answer as I have not tested it.Crumpton
@mitty *Calls (3) and (4) should execute synchronously on the main UI thread.Crumpton
S
0

My experience is that some calls might need message processing to function properly. Try to pump some messages between your calls to Navigate, Stop etc. When working with the web browser interfaces I PostMessage myself often to trigger the next step to make sure the previous step had time to complete.

The problem might be related to your child thread. You cannot access web browser interfaces between threads without some additional work. COM needs to be initialized as single-threaded apartment (STA). And you need to follow the rules of STAs:

  • Every object should live on only one thread (within a single-threaded apartment). Initialize the COM library for each thread.
  • Marshal all pointers to objects when passing them between apartments.
  • Each single-threaded apartment must have a message loop to handle calls from other processes and apartments within the same process. Single-threaded apartments without objects (client only) also need a message loop to dispatch the broadcast messages that some applications use.
  • ...
Spongin answered 28/11, 2011 at 10:56 Comment(3)
Thanks for your input. But there is no problem with marshalling btw threads - and threads are successfully able to control IE (navigate) There is no issue in between multiple calls to IE control - works fine. Well I have just tested the same scenario with a new Win32 App with main thread and worker threads in both cases IE does not terminates.Shippen
You are not allowed to make calls from a thread that didn't create the browser control to the browser control without doing some marshalling. Maybe the marshalling is done behind the scenes, but it is necessary. Just making the call might appear to work, but who knows what messages get lost. But are you saying that also in a single threaded scenario the problem persists?Spongin
Yes. If I use DialogBox and drop a IEControl on it as a resource and Dialogbox is derived from CAxDialogImpl<> - then while destroywindow() of dialogbox is automatically doing the cleanup();Shippen
S
0

If I use DialogBox and drop a IEControl on it as a resource and DialogBox is derived from CAxDialogImpl<> - then while I call DestroyWindow() of dialogBox then it is automatically doing the cleanup() - which is what I required. But originally I wanted to get rid of DialogBox itself and use IEControl directly on my Window, it seems not..

Shippen answered 30/11, 2011 at 13:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.