• 0

[C#] attach event to window exit


Question

I launch an application through another application. I can get the window handle of the application, and I want to add an event to it when it is closed.

When it is closed, I want to do something in my applcation... so I'm looking to attach to a window I guess, and when its Exited, throw an event and do something.

Any ideas?

Link to comment
https://www.neowin.net/forum/topic/616922-c-attach-event-to-window-exit/
Share on other sites

7 answers to this question

Recommended Posts

  • 0

Something along the lines of this?

using System.Windows.Forms;

class ClassName : Form
{
	//some class variables, methods, delegates, etc. ?
	ClassName ()
	{
		//some other things?
		this.FormClosing += new FormClosingEventHandler(formClosing);
	}

	void formClosing (object sender, FormClosingEventArgs)
	{
		//If you are using multithreaded programming, make sure to notify the threads that the app is
		//	closing somehow. Otherwise, you'll get exceptions (in the console if compiled as a console app)

		// THROW YOUR EVENT SOMEWHERE IN HERE
	}

	public static void Main (string[] args)
	{
		Application.Run(new ClassName());
	}
}

  • 0

My title and post are unclear...

I basically only have the Window handle, an IntPtr of the application of which I want to attach events to. Whenever this external window is closed, I want an event to be called in my application.

I understand events and the simplicity... .Exited or whatever, but I ONLY have the IntPtr handle to the window.

  • 0

You'll want to hook into Windows and monitor the WM_Close (WM_CLOSE = 0x0010) event and check the handle you have against the handle of the window being closed. You do this by overriding the WndProc event. Or you can set up a system wide hook The following is what I use to set this up. Just copy this into a .cs file (ex. Hook.cs) and create a reference to this in your form.

using System;
using System.ComponentModel;
using System.Runtime.InteropServices;

namespace Hook
{
	public delegate void OnForegroundWindowChangedDelegate(IntPtr hWnd);
	public delegate void OnWindowMinimizeStartDelegate(IntPtr hWnd);
	public delegate void OnWindowMinimizeEndDelegate(IntPtr hWnd);
	public delegate void OnWindowDestroyDelegate(IntPtr hWnd);

	public sealed class Hooks
	{
		#region Windows API

		private enum SystemEvents : uint
		{
			EVENT_SYSTEM_DESTROY = 0x8001,
			EVENT_SYSTEM_MINIMIZESTART = 0x0016,
			EVENT_SYSTEM_MINIMIZEEND = 0x0017,
			EVENT_SYSTEM_FOREGROUND = 0x0003
		}

		private const uint WINEVENT_OUTOFCONTEXT = 0x0000;

		private delegate void WinEventDelegate(
			IntPtr hWinEventHook,
			uint eventType,
			IntPtr hWnd,
			int idObject,
			int idChild,
			uint dwEventThread,
			uint dwmsEventTime);

		[DllImport("User32.dll", SetLastError = true)]
		private static extern IntPtr SetWinEventHook(
			uint eventMin,
			uint eventMax,
			IntPtr hmodWinEventProc,
			WinEventDelegate lpfnWinEventProc,
			uint idProcess,
			uint idThread,
			uint dwFlags);

		[DllImport("user32.dll")]
		private static extern bool UnhookWinEvent(
			IntPtr hWinEventHook
			);

		#endregion

		private WinEventDelegate dEvent;
		private IntPtr pHook;
		public OnForegroundWindowChangedDelegate OnForegroundWindowChanged;
		public OnWindowMinimizeStartDelegate OnWindowMinimizeStart;
		public OnWindowMinimizeEndDelegate OnWindowMinimizeEnd;
		public OnWindowDestroyDelegate OnWindowDestroy;

		public Hooks()
		{
			dEvent = this.WinEvent;
			pHook = SetWinEventHook(
				(uint)SystemEvents.EVENT_SYSTEM_DESTROY ,
				(uint)SystemEvents.EVENT_SYSTEM_DESTROY ,
				IntPtr.Zero,
				dEvent,
				0,
				0,
				WINEVENT_OUTOFCONTEXT
				);

			if (IntPtr.Zero.Equals(pHook)) throw new Win32Exception();

			GC.KeepAlive(dEvent);
		}

		private void WinEvent(IntPtr hWinEventHook, uint eventType, IntPtr hWnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
		{
			switch (eventType)
			{
				case (uint)SystemEvents.EVENT_SYSTEM_DESTROY:
					if (OnWindowDestroy != null) OnWindowDestroy(hWnd);
					break;

				//extend here when required
			}
		}

		~Hooks()
		{
			if (!IntPtr.Zero.Equals(pHook)) UnhookWinEvent(pHook);
			pHook = IntPtr.Zero;
			dEvent = null;

			OnWindowDestroy = null;
		}
	}
}

Then to use this, insert this into your form:

Hook hook = new Hook();

And then in your form's loading event insert this to set up an event for the hook:

hook.OnWindowDestroy += OnWindowDestroyDelegate(window_Destroyed);

private void window_Destroyed(IntPtr hWnd)
{
	 if (hWnd == {the handle you're looking for})
	 {
		  //Do whatever you need here!
	 }
}

Hope it helps.

  • 0

This is great... one problem... (I'm awful with delegates, I really need a book).

The hook setup gives me an error:

hook.OnWindowDestroy += OnWindowDestroyDelegate(window_Destroyed);

project.OnWindowDestroyDelegate' is a 'type' but is used like a 'variable'

I copied your code exactly, but just changed the namespace to my project.. I think that's correct...

  • 0
  zackiv31 said:
This is great... one problem... (I'm awful with delegates, I really need a book).

The hook setup gives me an error:

hook.OnWindowDestroy += OnWindowDestroyDelegate(window_Destroyed);

project.OnWindowDestroyDelegate' is a 'type' but is used like a 'variable'

I copied your code exactly, but just changed the namespace to my project.. I think that's correct...

Sorry, I forgot to type 'new' in there. The correct line should be:

hook.OnWindowDestroy += new OnWindowDestroyDelegate(window_Destroyed);

  • 0
  zackiv31 said:
This is great... one problem... (I'm awful with delegates, I really need a book).

The hook setup gives me an error:

hook.OnWindowDestroy += OnWindowDestroyDelegate(window_Destroyed);

project.OnWindowDestroyDelegate' is a 'type' but is used like a 'variable'

I copied your code exactly, but just changed the namespace to my project.. I think that's correct...

This is really very helpful post.

One question: I want to handle other message, like WM_PAINT, WM_MOVE, etc. in this case how can I get the message codes?

I tried declaring EVENT_SYSTEM_PAINT = 0x000F but this is not working.

Kindly suggest.

This topic is now closed to further replies.
  • Recently Browsing   0 members

    • No registered users viewing this page.
  • Posts

    • The article clearly states multiple times that he will DONATE his wealth. There's no mention of any loan, but haters gonna hate. He doesn't need to do this, you know? He could just give all that money to his kids and call it a day.
    • highly doubt that, he's giving away his wealth, he's been doing it for years now
    • Might be just about usable in about 5 years.
    • New Outlook for Windows gets a major boost with June 2025 Update by Pradeep Viswanathan Despite widespread criticism, Microsoft has remained focused on replacing the classic Outlook for Windows with the new web-based Outlook app for everyone. Every month, Microsoft releases updates to the new Outlook app based on user feedback. Today, Microsoft released the June 2025 update for Outlook for Windows with several improvements, including some of the most requested features by Outlook users. With this latest update, Microsoft has improved support for .pst (Outlook Data File) files. You can now reply to and forward emails in a stored .pst file. Microsoft is also working on further improving support for .pst files in the new Outlook for Windows. If you're using the new Outlook app with your personal Microsoft account that has access to Copilot Pro or AI credits through a Microsoft 365 Personal or Family subscription, Copilot features will now be available even for other personal email accounts configured in the Outlook app. This Copilot sharing feature works with email addresses such as Outlook.com, Hotmail.com, Live.com, MSN.com, and third-party providers like Gmail, Yahoo, and iCloud. Microsoft has also added the ability to easily move emails between personal accounts. This feature is disabled by default for enterprise users, but admins can enable it if needed. With this update, Microsoft has increased the default mail sync window in offline mode from 7 days to 30 days. Additionally, you can now access search folders and cancel an email after selecting Send in offline mode. This new update also brings email coaching support through Copilot. Copilot can now suggest adjustments to tone, clarity, and reader sentiment before you hit Send. If you are annoyed with Copilot, you can now disable Copilot completely by going to the Copilot > Copilot control page in the Settings window. In this release, Microsoft has added the ability to add shared folders to your Favorites, making it easier to access content directly from the Favorites list. Finally, an "External" tag will be added to external contact suggestions that appear in the dropdown menu when entering contacts in the email compose form, helping you distinguish between your organization's and external contacts.
    • "give" I believe he will give loans and drown the countries in debt
  • Recent Achievements

    • Week One Done
      Adam Todd earned a badge
      Week One Done
    • Contributor
      Ed B went up a rank
      Contributor
    • One Month Later
      moporcho earned a badge
      One Month Later
    • One Month Later
      Parotel earned a badge
      One Month Later
    • Reacting Well
      Cryptecks earned a badge
      Reacting Well
  • Popular Contributors

    1. 1
      +primortal
      211
    2. 2
      snowy owl
      156
    3. 3
      ATLien_0
      134
    4. 4
      Xenon
      120
    5. 5
      +FloatingFatMan
      113
  • Tell a friend

    Love Neowin? Tell a friend!