0

We are using an Internet Explorer object (Interop.SHDocVw, Version=1.1.0.0, Culture=neutral, PublicKeyToken=null) to open a explorer outside a WPF application.

We need to know when the explorer closes so we handle the OnQuit event but we are receiving the event multiple times due to unknown reasons depending on the URL.

The following POC demonstrates the issue:

using System;

namespace InternetExplorerQuitPOC
{
    class Program
    {
        static void Main(string[] args)
        {
            do
            {
                SHDocVw.InternetExplorer internetExplorer;

                internetExplorer = new SHDocVw.InternetExplorer();
                internetExplorer.OnQuit += OnInternetExplorerOnOnQuit;

                internetExplorer.ToolBar = 1;
                internetExplorer.StatusBar = true;
                internetExplorer.MenuBar = true;
                internetExplorer.Visible = true;

                object url = "https://www.notariado.org";

                internetExplorer.Navigate2(ref url);
            } while (Console.ReadKey() != null);
        }

        private static void OnInternetExplorerOnOnQuit()
        {
            Console.Out.WriteLine("Quit fired");
        }
    }
}
Ignacio Soler Garcia
  • 21,122
  • 31
  • 128
  • 207
  • I also observed this behavior in a BHO running inside an IE process, so I stopped using it as an indication of exit. In my case though, since BHO implements IObjectWithSite, the most reliable indication was SetSite called with NULL. IE creates a new instance of BHO per tab, so I had to count -- when the last tab was gone, I knew that IE is closing. This probably doesn't help much in your case, but may give you some direction of thought. – felix-b Jan 31 '18 at 11:39
  • @felix-b: thanks for the info. I'm sorry if this is a silly questoin but what's a BHO? :) – Ignacio Soler Garcia Jan 31 '18 at 14:03
  • 1
    BHO stands for Browser Helper Object, this is how Interned Explorer add-ons are named. These are COM objects loaded in-process by Internet Explorer. – felix-b Jan 31 '18 at 14:05
  • All BHO implement IObjectWithSite. Once IE "co-creates" an instance of a BHO, it invokes BHO's IObjectWithSite.SetSite() passing an object that implements IWebBrowser2. Usually, BHO also implements DWebBrowserEvents2. In SetSite, BHO subscribes to DWebBrowserEvents2 events using the received IWebBrowser2 object. In the end of BHO's lifecycle (when the associated tab is closed), IE invokes SetSite with the NULL pointer. – felix-b Jan 31 '18 at 14:13
  • @felix-b: oh, then it's probably not valid for us as we are just automating IE, we are not a plug-in ... thanks anyway. – Ignacio Soler Garcia Jan 31 '18 at 14:30
  • 1
    Of course your case is different -- but the OnQuit event behaves in the same useless way as with BHO -- that was my point – felix-b Jan 31 '18 at 14:33
  • @felix-b: I agree. I've asked in the M$ forums as well, maybe I get some answers there. I was thinking on filling a bug as well. – Ignacio Soler Garcia Jan 31 '18 at 14:35

2 Answers2

0

It turns out that the OnQuit event is raised in more situations than just closing the browser, for example, if the page has an inside IE will raise the OnQuit as well so the OnQuit event is not reliable to know when IE has been closed so I've found a way to know it in a reliable way:

        uint processId;
        this.internetExplorer = new InternetExplorer();

        NativeMethods.GetWindowThreadProcessId(new IntPtr(this.internetExplorer.HWND), out processId);
        this.internetExplorerProcess = Process.GetProcessById(Convert.ToInt32(processId));
        this.internetExplorerProcess.EnableRaisingEvents = true;
        this.internetExplorerProcess.Exited += this.OnQuit;

This code will call the OnQuit only when the process is finished as it should do the InternetExplorer object (sigh).

Ignacio Soler Garcia
  • 21,122
  • 31
  • 128
  • 207
0

For Ignacio.

Your solution is not 100% valid, internet explorer reuses the same processes when opening different browsers, which causes the Exited event to only run on the Close of the last browser that shares the process, this may be a browser that does not interest us.

The steps I have followed to implement a valid solution are:

  1. Create a Process.Start("iexplorer", "- noframemerging") -noframemerging: Internet Explorer 8 and later versions. Prevents Internet Explorer from opportunistically merging new frame processes into existing frame processes. This has the effect of preventing session merging as well, because session merging can only happen with a merged frame process.

    This guarantees that our navigation is not merged with other Internet Explorer processes.

  2. Associate that process with SHDocVw.InternetExplorer object.

  3. Configure SHDocVw.InternetExplorer object, window size, visibility of the toolbar ...

  4. Subscribe to Process Exited.

  5. SHDocVw.InternetExplorer.Navigate2 ("url")

  6. Close the new Internet Explorer process.

  7. We will now receive the Exited event of the desired process.

Point 1 is the key to solving the problem. Sorry for my level of English. (I will post an example code)

Ignacio, we miss you :P

Javi Quirós
  • 49
  • 11