Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

.NET Console Application Exit Event

In .NET, is there a method, such as an event, for detecting when a console application is exiting? I need to clean up some threads and COM objects.

I am running a message loop, without a form, from the console application. A DCOM component that I am using seems to require that the application pump messages.

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

I have also tried adding a handler to Application.ApplicationExit and Application.ThreadExit events, but they are not firing. Perhaps that is because I am not using a form.

like image 688
user79755 Avatar asked Jul 13 '09 14:07

user79755


People also ask

How do I stop C# console applications from closing automatically?

The first solution is to run the application without debugging by using Ctrl+F5 instead of just F5. The console window will remain open when the program has finished. The disadvantage of this is that you lose Visual Studio's debug information.

How do I exit console?

Exit a Console Application With the return Method in C# The return statement ends the execution of a method and returns the control to the calling or the main method. We can use the return statement inside the main() function to end our console application's execution.


2 Answers

You can use the ProcessExit event of the AppDomain:

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 full example program with an empty "message pump" running on a separate thread, that allows the user to input a quit command in the console to close down the application gracefully. After the loop in MessagePump you will probably want to clean up resources used by the thread in a nice manner. It's better to do that there than in ProcessExit for several reasons:

  • Avoid cross-threading problems; if external COM objects were created on the MessagePump thread, it's easier to deal with them there.
  • There is a time limit on ProcessExit (3 seconds by default), so if cleaning up is time consuming, it may fail if pefromed within that event 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's 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");     } } 
like image 179
Fredrik Mörk Avatar answered Sep 22 '22 14:09

Fredrik Mörk


Here is a complete, very simple .NET solution that works in all versions of Windows. Simply paste it into a new project, run it and try Ctrl + C to view 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..");         }     }  } 
like image 24
JJ_Coder4Hire Avatar answered Sep 18 '22 14:09

JJ_Coder4Hire