How to make a console app exit gracefully when it is closed

.net, c#, winapi

Solution

You can use DLLImport to import SetConsoleControlHandler and use it to register an event handler for the closed event (and others), here's an example snippet that shows it working (it will write closed in Log.txt whem you click the X to close the console):

class Program
{
    [DllImport("Kernel32")]
    public static extern bool SetConsoleCtrlHandler(HandlerRoutine Handler, bool Add);

    // A delegate type to be used as the handler routine 
    // for SetConsoleCtrlHandler.
    public delegate bool HandlerRoutine(CtrlTypes CtrlType);

    // An enumerated type for the control messages
    // sent to the handler routine.
    public enum CtrlTypes
    {
        CTRL_C_EVENT = 0,
        CTRL_BREAK_EVENT,
        CTRL_CLOSE_EVENT,
        CTRL_LOGOFF_EVENT = 5,
        CTRL_SHUTDOWN_EVENT
    }

    private static bool ConsoleCtrlCheck(CtrlTypes ctrlType)
    {
        if (ctrlType == CtrlTypes.CTRL_CLOSE_EVENT)
            File.AppendAllText(@"Log.txt", "closed");

        return true;
    }

    private static void Main(string[] args)
    {
        SetConsoleCtrlHandler(new HandlerRoutine(ConsoleCtrlCheck), true);
        Console.WriteLine("Close me");
        Console.ReadLine();
    }
}

Source

Problem

I wrote this little program to demonstrate the point of the question: ``` using System; using System.IO; using System.Threading; class Program { static void Main(string[] args) { using (var disp = new MyDisp()) { using (var ewhLocalExit = new EventWaitHandle(false, EventResetMode.ManualReset)) { Console.WriteLine("Enter Ctrl+C to terminate the app."); Console.CancelKeyPress += (_, e) => { e.Cancel = true; ewhLocalExit.Set(); }; ewhLocalExit.WaitOne(); } } File.AppendAllText("Log.txt", "Terminated.\n"); } } class MyDisp : IDisposable { public MyDisp() { File.AppendAllText("Log.txt", "Started.\n"); } public void Dispose() { File.AppendAllText("Log.txt", "Disposed.\n"); } } ``` When I run it and press Ctrl+C, I see "Started.Disposed.Terminated." in Log.txt When I run it and close it with the mouse, I see only "Started." How do I make exit gracefully, so that I at least could see "Disposed." ?

Original source