Monday, March 5, 2012

Intercept Termination of a Console Applications

Sometimes an application is terminated during the execution of a critical action - for example by the user.
If you want to finish this action or use a different code to exit, in Windows Forms Applications simply the events FormClosed and FormClosing can be used.
In console applications they are not avaible. To be still able to react to the unexpected ending of the application, we use the function SetConsoleCtrlHandler().
With this we can register a function at the application, which is called when the program quits.
SetConsoleCtrlHandler() expects 2 arguments, the first is the delegate to the function which is to be used, the second a Boolean value which determines, if the handler is to be added or deleted.
The function, which is called when exiting, expects an enumeration is parameter, which specifies the event which causes the termination, and has always to return false.
In the code we first create a delegate of the desired signature:
private delegate bool EventHandler(CtrlType e)

Then we create a variable of the previously defined type:
static EventHandler ConsoleCloseHandler
.
This we assign now our function we want to use and register this at the application:
ConsoleCloseHandler += new EventHandler(Console_Closed);
SetConsoleCtrlHandler(ConsoleCloseHandler, true);

In the function Console_Closed() the reason of quitting is saved in the argument, this can be determined and used.
The enumeration used by me contains 4 events: The quitting via the key combination Ctrl + C, the quitting by clicking "X", the quitting because the user loggs off and the quitting because of shutting down.
I hope the following source code explains this:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Runtime.InteropServices;

namespace ConsoleApplication1
{
    class Program
    {
        [DllImport("Kernel32")]
        private static extern bool SetConsoleCtrlHandler(EventHandler handler, bool add);

        enum CtrlType
        {
            CTRL_C_EVENT = 0,
            CTRL_CLOSE_EVENT = 2,
            CTRL_LOGOFF_EVENT = 5,
            CTRL_SHUTDOWN_EVENT = 6
        }

        private delegate bool EventHandler(CtrlType e);
        static EventHandler ConsoleCloseHandler;

        static void Main(string[] args)
        {
            ConsoleCloseHandler += new EventHandler(Console_Closed);
            SetConsoleCtrlHandler(ConsoleCloseHandler, true);

            while (true)
            {
                // infinite loop
            }
        }

        private static bool Console_Closed(CtrlType e)
        {
            switch (e)
            {
                case CtrlType.CTRL_C_EVENT:
                    Console.WriteLine("Ctrl + C");
                    Console.ReadLine();
                    break;
                case CtrlType.CTRL_LOGOFF_EVENT:
                    Console.WriteLine("Log Off");
                    Console.ReadLine();
                    break;
                case CtrlType.CTRL_SHUTDOWN_EVENT:
                    Console.WriteLine("Shutdown");
                    Console.ReadLine();
                    break;
                case CtrlType.CTRL_CLOSE_EVENT:
                    Console.WriteLine("Close");
                    Console.ReadLine();
                    break;
                default:
                    Console.WriteLine("other");
                    Console.ReadLine();
                    break;
            }

            return true;
        }
    }
}

No comments:

Post a Comment