.NET Console Application Exit Event

In .NET, is there a method, such as an event, for detecting the exit of a Console application? I need to clear some threads and COM objects.

I am starting a formless message loop from a console application. The DCOM component that I use apparently requires application pump messages.

I tried adding a handler to Process.GetCurrentProcess.Exited and Process.GetCurrentProcess.Disposed.

I also tried adding the Application.ApplicationExit and Application.ThreadExit event handler, but they do not fire. Perhaps this is because I am not using a form.

+47
complexity-theory console-application
Jul 13 '09 at 14:38
source share
6 answers

You can use the ProcessExit AppDomain event:

 class Program { static void Main(string[] args) { AppDomain.CurrentDomain.ProcessExit += new EventHandler(CurrentDomain_ProcessExit); // do some work } static void CurrentDomain_ProcessExit(object sender, EventArgs e) { Console.WriteLine("exit"); } } 

Update

Here is a complete sample program with an empty “message pump” running in a separate thread that allows the user to enter the quit command in the console to gracefully close the application. After a loop in MessagePump, you probably want to clear the resources used by the stream beautifully. Better to do it there than in ProcessExit, for several reasons:

  • Avoid cross flow issues; if external COM objects were created in the MessagePump stream, it is easier to deal with them.
  • There is a time limit on ProcessExit (3 seconds by default), therefore, if cleaning takes a long time, it may fail if it was selected in this handler.

Here is the code:

 class Program { private static bool _quitRequested = false; private static object _syncLock = new object(); private static AutoResetEvent _waitHandle = new AutoResetEvent(false); static void Main(string[] args) { AppDomain.CurrentDomain.ProcessExit += new EventHandler(CurrentDomain_ProcessExit); // start the message pumping thread Thread msgThread = new Thread(MessagePump); msgThread.Start(); // read input to detect "quit" command string command = string.Empty; do { command = Console.ReadLine(); } while (!command.Equals("quit", StringComparison.InvariantCultureIgnoreCase)); // signal that we want to quit SetQuitRequested(); // wait until the message pump says it done _waitHandle.WaitOne(); // perform any additional cleanup, logging or whatever } private static void SetQuitRequested() { lock (_syncLock) { _quitRequested = true; } } private static void MessagePump() { do { // act on messages } while (!_quitRequested); _waitHandle.Set(); } static void CurrentDomain_ProcessExit(object sender, EventArgs e) { Console.WriteLine("exit"); } } 
+49
Jul 13 '09 at 14:42
source share

Here is a complete, very simple .NET solution that works on all versions of Windows. Just paste it into a new project, run it and try CTRL-C to see how it handles it:

 using System; using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.Threading; namespace TestTrapCtrlC{ public class Program{ static bool exitSystem = false; #region Trap application termination [DllImport("Kernel32")] private static extern bool SetConsoleCtrlHandler(EventHandler handler, bool add); private delegate bool EventHandler(CtrlType sig); static EventHandler _handler; enum CtrlType { CTRL_C_EVENT = 0, CTRL_BREAK_EVENT = 1, CTRL_CLOSE_EVENT = 2, CTRL_LOGOFF_EVENT = 5, CTRL_SHUTDOWN_EVENT = 6 } private static bool Handler(CtrlType sig) { Console.WriteLine("Exiting system due to external CTRL-C, or process kill, or shutdown"); //do your cleanup here Thread.Sleep(5000); //simulate some cleanup delay Console.WriteLine("Cleanup complete"); //allow main to run off exitSystem = true; //shutdown right away so there are no lingering threads Environment.Exit(-1); return true; } #endregion static void Main(string[] args) { // Some biolerplate to react to close window event, CTRL-C, kill, etc _handler += new EventHandler(Handler); SetConsoleCtrlHandler(_handler, true); //start your multi threaded program here Program p = new Program(); p.Start(); //hold the console so it doesn't run off the end while(!exitSystem) { Thread.Sleep(500); } } public void Start() { // start a thread and start doing some processing Console.WriteLine("Thread started, processing.."); } } } 
+17
Apr 10 '14 at 18:39
source share

An application is a server that simply starts until the system turns off or receives Ctrl + C or the console window is closed.

Due to the extraordinary nature of the application, it is impossible to "gracefully" exit. (Perhaps I could encode another application that would send a “shutdown” message to the server, but that would be redundant for one application and still not enough for certain circumstances, for example, when the server (actual OS) actually shuts down.)

Due to these circumstances, I added " ConsoleCtrlHandler ", where I stop my threads and clear my COM objects, etc.

 Public Declare Auto Function SetConsoleCtrlHandler Lib "kernel32.dll" (ByVal Handler As HandlerRoutine, ByVal Add As Boolean) As Boolean Public Delegate Function HandlerRoutine(ByVal CtrlType As CtrlTypes) As Boolean Public Enum CtrlTypes CTRL_C_EVENT = 0 CTRL_BREAK_EVENT CTRL_CLOSE_EVENT CTRL_LOGOFF_EVENT = 5 CTRL_SHUTDOWN_EVENT End Enum Public Function ControlHandler(ByVal ctrlType As CtrlTypes) As Boolean . .clean up code here . End Function Public Sub Main() . . . SetConsoleCtrlHandler(New HandlerRoutine(AddressOf ControlHandler), True) . . End Sub 

This setting seems to work fine. Here is a link to some C # code for the same.

+16
Jul 13 '09 at 15:09
source share

For the case of CTRL + C, you can use this:

 // Tell the system console to handle CTRL+C by calling our method that // gracefully shuts down. Console.CancelKeyPress += new ConsoleCancelEventHandler(Console_CancelKeyPress); static void Console_CancelKeyPress(object sender, ConsoleCancelEventArgs e) { Console.WriteLine("Shutting down..."); // Cleanup here System.Threading.Thread.Sleep(750); } 
+7
Jul 13 '09 at 15:13
source share

If you are using a console application and you are forwarding messages, can you not use the WM_QUIT message?

+1
Jul 13 '09 at 14:43
source share

As a good example, it may be appropriate to go to this project and see how to process the outgoing processes grammatically or in this fragment from the VM found here

  ConsoleOutputStream = new ObservableCollection<string>(); var startInfo = new ProcessStartInfo(FilePath) { WorkingDirectory = RootFolderPath, Arguments = StartingArguments, RedirectStandardOutput = true, UseShellExecute = false, CreateNoWindow = true }; ConsoleProcess = new Process {StartInfo = startInfo}; ConsoleProcess.EnableRaisingEvents = true; ConsoleProcess.OutputDataReceived += (sender, args) => { App.Current.Dispatcher.Invoke((System.Action) delegate { ConsoleOutputStream.Insert(0, args.Data); //ConsoleOutputStream.Add(args.Data); }); }; ConsoleProcess.Exited += (sender, args) => { InProgress = false; }; ConsoleProcess.Start(); ConsoleProcess.BeginOutputReadLine(); } } private void RegisterProcessWatcher() { startWatch = new ManagementEventWatcher( new WqlEventQuery($"SELECT * FROM Win32_ProcessStartTrace where ProcessName = '{FileName}'")); startWatch.EventArrived += new EventArrivedEventHandler(startProcessWatch_EventArrived); stopWatch = new ManagementEventWatcher( new WqlEventQuery($"SELECT * FROM Win32_ProcessStopTrace where ProcessName = '{FileName}'")); stopWatch.EventArrived += new EventArrivedEventHandler(stopProcessWatch_EventArrived); } private void stopProcessWatch_EventArrived(object sender, EventArrivedEventArgs e) { InProgress = false; } private void startProcessWatch_EventArrived(object sender, EventArrivedEventArgs e) { InProgress = true; } 
0
Feb 01
source share



All Articles