Jose Ramon
Jose Ramon

Reputation: 5444

Detect console exit event

I have created a console application which has a method that stores kinect stream to hard disk. I want to capture console exit event in order to close the kinect stream since I have issues when the console exit from close event. I want to find a way to detect the exit event of the console. I came across solutions like the following one. I add the following code to my app:

[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)
{
   switch (sig)
   {
            case CtrlType.CTRL_C_EVENT:
            case CtrlType.CTRL_LOGOFF_EVENT:
            case CtrlType.CTRL_SHUTDOWN_EVENT:
            case CtrlType.CTRL_CLOSE_EVENT:
            default:
                return false;
    }
}

And in the main function:

  Program obj = new Program(dirPath + args[3] + "_" + args[4]);
  _handler += new EventHandler(Handler);
  SetConsoleCtrlHandler(_handler, true);

  Console.ReadLine();

I am wandering firstly if I can import handler event to a boolean variable and secondly how can I give it as an input to program constructor in order to close my stream.

EDIT: My program constructor:

public Program(string filePath)
    {

        Thread thread = new Thread(() => writeRGSStream(file));
        thread.Start();
        writeSkelFiles(file);

    }

I want to give the flag input inside the writeRGSStream method. Can I call

SetConsoleCtrlHandler(new HandlerRoutine(ConsoleCtrlCheck), true);

inside that method in order to get the flag value?

Upvotes: 2

Views: 2087

Answers (3)

bb441db
bb441db

Reputation: 294

Use the CancelKeyPress event (fired on CTRL+C).

Console.CancelKeyPress += Console_CancelKeyPress;

do things before close here

private static void Console_CancelKeyPress(object sender, ConsoleCancelEventArgs e)
{
    Process.GetCurrentProcess().CloseMainWindow();
}

Hopefully this is what you tried to do.

Upvotes: 1

Hans Passant
Hans Passant

Reputation: 941585

  return false;

This does not do what you hope it does. You cannot cancel a close request, the return value merely tells Windows whether it should call any other registered handlers. So whether you return true or false has no affect on the outcome, the OS will always terminate the program.

So anything you need to do must be done inside the callback method. Beware that you have very limited options. After all, your main thread is busy writing that file, you cannot delete it. Nor is it a real fix at all, you still have trouble if your app terminates for any other reason. Like an unhandled exception, the user killing it with Task Manager or somebody tripping over the power cord and unplugging the machine.

Just write smarter code, create the file with a temporary name and rename the file after you are done writing it. Now you never care that your program gets interrupted for any reason.

Upvotes: 1

Maxim Goncharuk
Maxim Goncharuk

Reputation: 1333

Look at this example, it works fine:

Main

private static bool isclosing = false;
        static void Main(string[] args)
        {
            SetConsoleCtrlHandler(new HandlerRoutine(ConsoleCtrlCheck), true);

            Console.WriteLine("CTRL+C,CTRL+BREAK or suppress the application to exit");
            while (!isclosing) ;

        }

Console check

private static bool ConsoleCtrlCheck(CtrlTypes ctrlType)
        {
            // Put your own handler here
            switch (ctrlType)
            {
                case CtrlTypes.CTRL_C_EVENT:
                    isclosing = true;
                    Console.WriteLine("CTRL+C received!");
                    break;

                case CtrlTypes.CTRL_BREAK_EVENT:
                    isclosing = true;
                    Console.WriteLine("CTRL+BREAK received!");
                    break;

                case CtrlTypes.CTRL_CLOSE_EVENT:
                    isclosing = true;
                    Console.WriteLine("Program being closed!");
                    break;

                case CtrlTypes.CTRL_LOGOFF_EVENT:
                case CtrlTypes.CTRL_SHUTDOWN_EVENT:
                    isclosing = true;
                    Console.WriteLine("User is logging off!");
                    break;

            }
            return true;
        }

And WinAPI part:

#region unmanaged
// Declare the SetConsoleCtrlHandler function
// as external and receiving a delegate.

[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
}

#endregion

Upvotes: 5

Related Questions