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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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.

1
2
3
4
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.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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.

Download Code

References

Add your control on top of another application – By Shai Raiten

About author
Author Image
Utkarsh Shigihalli
Utkarsh is passionate about software development and has more than 12 years of work experience in the areas of Azure, VSTS, C# and TypeScript. He has developed numerous extensions for Visual Studio and Visual Studio Team Services. He is currently working as a Consultant in the United States.
Comments