Lately I am busy working on developing a small shell extension. There is a functionality in my shell extension, that user opens the .NET windows form by right clicking on a file (context menu). The user then decides to close the parent explorer window (instead of closing the windows form opened). Now, in such a case I would like to close the windows form too. So, to achieve this I had to subscribe to the close event of the windows explorer. The below code shows the how to achieve the same. Although I am monitoring window close (destroy event), this can done for any process in Windows for which you have the handler (For ex: Notepad). Read more at link provided in “References” section.
So we are going to do it by performing following steps:
- Find out the handle of the window we are interested in
- Hook the Destroy event
- When the event is raised, perform the desired operation
Find out the handle of the window we are interested in
public static IntPtr Find(string moduleName, string mainWindowTitle)
{
//Search the window using Module and Title
IntPtr WndToFind = NativeMethods.FindWindow(moduleName, mainWindowTitle);
if (WndToFind.Equals(IntPtr.Zero))
{
if (!string.IsNullOrEmpty(mainWindowTitle))
{
//Search window using Title only.
WndToFind = NativeMethods.FindWindowByCaption(WndToFind, mainWindowTitle);
if (WndToFind.Equals(IntPtr.Zero))
return new IntPtr(0);
}
}
return WndToFind;
}
We call the Find method as below. P.S: In my shell extension this window handler is automatically given by the library to me, so I do not use Find method.
string ModuleName = "explorer.exe";
string MainWindowTitle = "Libraries";
var targetWnd = Find(ModuleName, MainWindowTitle);
Hook the Destroy event
Put the below code in your constructor or initialization method.
public MainWindow()
{
InitializeComponent();
Dictionary<AccessibleEvents, NativeMethods.WinEventProc> events = InitializeWinEventToHandlerMap();
//Hook window close event - close our HoverContorl on Target window close.
NativeMethods.WinEventProc eventHandler = new NativeMethods.WinEventProc(events[AccessibleEvents.Destroy].Invoke);
GCHandle gch = GCHandle.Alloc(eventHandler);
_garbageHook = NativeMethods.SetWinEventHook(AccessibleEvents.Destroy, AccessibleEvents.Destroy, IntPtr.Zero, eventHandler
, 0, 0, NativeMethods.SetWinEventHookParameter.WINEVENT_OUTOFCONTEXT);
}
private Dictionary<AccessibleEvents, NativeMethods.WinEventProc> InitializeWinEventToHandlerMap()
{
Dictionary<AccessibleEvents, NativeMethods.WinEventProc> dictionary = new Dictionary<AccessibleEvents, NativeMethods.WinEventProc>();
//You can add more events like ValueChanged - for more info please read -
//http://msdn.microsoft.com/en-us/library/system.windows.forms.accessibleevents.aspx
dictionary.Add(AccessibleEvents.Destroy, new NativeMethods.WinEventProc(this.DestroyCallback));
return dictionary;
}
When the event is raised, perform the desired operation
private void DestroyCallback(IntPtr winEventHookHandle, AccessibleEvents accEvent, IntPtr windowHandle,
int objectId, int childId, uint eventThreadId, uint eventTimeInMilliseconds)
{
//Make sure AccessibleEvents equals to LocationChange and the current window is the Target Window.
if (accEvent == AccessibleEvents.Destroy && windowHandle.ToInt32() == _targetWindowHandler.ToInt32())
{
//Queues a method for execution. The method executes when a thread pool thread becomes available.
ThreadPool.QueueUserWorkItem(new WaitCallback(this.DestroyHelper));
}
}
private void DestroyHelper(object state)
{
MessageBox.Show("Good bye!");
//Removes an event hook function created by a previous call to
NativeMethods.UnhookWinEvent(_garbageHook);
}
This demo application can be downloaded from below provided link, where in I am opening the explorer window and listening to close event. On close I am showing a simple message box.
References
Add your control on top of another application – By Shai Raiten