I am writing a win32 application by C++, and I want it to do something when all iexplorer.exe were closed.
I know that SetWindowsHook() may be useful in my case.
But if I have no idea about the process or thread ID of IE, because every time open IE would get a different thread ID.
If I do not use timer to check the process list to get the ID of iexplorer, does there have another approach to listen close event of IE in my win32 application?
The object for IE is called InternetExplorer. TheShellWindows object is a collection of InternetExplorer objects. But here it gets complicated. Not all InternetExplorer objects are what you would call an IE window. Some of them are "Windows Explorer" windows. See About the Browser (Internet Explorer).
The following is a managed C++ console program that lists the existing windows and sets a count of the number of existing windows. Then it uses WindowRegistered and WindowRevoked events to monitor creation and closing of windows. Those event are not documented very well. The sample below uses the Document member of each InternetExplorer object to determine if the window has HTML. However see the comment in c# - Distinguishing IE windows from other windows when using SHDocVw; it is possible for a IE window to not have HTML in it.
Note that the following sample is using an AutoResetEvent to keep the program going since it is a console program.
The following is the header:
#pragma once
#include <stdio.h>
#include <tchar.h>
#include <windows.h>
#include <ShlObj.h>
#include <comdef.h>
#include <vcclr.h>
The following is the program:
#include "stdafx.h"
using namespace System;
using namespace System::Threading;
static int Browsers = 0;
static gcroot<AutoResetEvent^> Event;
bool IsBrowser(SHDocVw::InternetExplorer ^ ie)
{
MSHTML::IHTMLDocument2^ Document;
try { Document = (MSHTML::IHTMLDocument2^)ie->Document; }
catch (Exception^ ex)
{
return false;
}
return Document != nullptr;
}
static void WindowRegistered(int lCookie) {
++Browsers;
Console::WriteLine("WindowRegistered");
}
static void WindowRevoked(int lCookie) {
--Browsers;
Console::WriteLine("WindowRevoked");
if (Browsers <= 0)
Event->Set();
}
int main(array<System::String ^> ^args)
{
SHDocVw::ShellWindows^ swList = gcnew SHDocVw::ShellWindowsClass();
Console::WriteLine(L"{0} instances", swList->Count);
for each (SHDocVw::InternetExplorer ^ ie in swList) {
Console::WriteLine(ie->LocationURL);
if (IsBrowser(ie)) {
Console::WriteLine("HTML document");
++Browsers;
}
else
Console::WriteLine("Not HTML");
}
if (Browsers == 0)
{
Console::WriteLine("No browsers");
return 0;
}
Event = gcnew AutoResetEvent(false);
swList->WindowRegistered += gcnew SHDocVw::DShellWindowsEvents_WindowRegisteredEventHandler(WindowRegistered);
swList->WindowRevoked += gcnew SHDocVw::DShellWindowsEvents_WindowRevokedEventHandler(WindowRevoked);
Event->WaitOne();
Console::WriteLine("No more browsers");
return 0;
}
Now I just realized that there is a problem with the way this works. The WindowRegistered and WindowRevoked handlers are incrementing the Browsers count even if the window is not an IE window. I don't know how to determine what window that the cookie passed to WindowRegistered and WindowRevoked represents. A few years ago I spent a couple of days or more tryinig to figure that out. So what you should do is to somehow re-list all the windows after each WindowRegistered and WindowRevoked event.
You need to add references for "Microsoft Internet Controls" (SHDocVw.dll) and "Microsoft HTML Object Library" (mshtml.dll) to the project. They are COM objects that should be in your "C:\Windows\System32" directory.