¿Cómo puedo capturar Ctrl+C (SIGINT) en una aplicación de consola C#?

Resuelto Nick Randell asked hace 15 años • 9 respuestas

Me gustaría poder capturar Ctrl+ Cen una aplicación de consola C# para poder realizar algunas limpiezas antes de salir. Cual es la mejor manera de hacer esto?

Nick Randell avatar Oct 07 '08 17:10 Nick Randell
Aceptado

Para esto se utiliza el evento Console.CancelKeyPress . Así es como se usa:

public static void Main(string[] args)
{
    Console.CancelKeyPress += delegate {
        // call methods to clean up
    };

    while (true) {}
}

Cuando el usuario presiona Ctrl+, Cel código en el delegado se ejecuta y el programa sale. Esto le permite realizar la limpieza llamando a los métodos necesarios. Tenga en cuenta que no se ejecuta ningún código después de que se ejecute el delegado.

Hay otras situaciones en las que esto no es suficiente. Por ejemplo, si el programa está realizando cálculos importantes que no se pueden detener de inmediato. En ese caso, la estrategia correcta podría ser decirle al programa que salga una vez completado el cálculo. El siguiente código ofrece un ejemplo de cómo se puede implementar esto:

class MainClass
{
    private static bool keepRunning = true;

    public static void Main(string[] args)
    {
        Console.CancelKeyPress += delegate(object? sender, ConsoleCancelEventArgs e) {
            e.Cancel = true;
            MainClass.keepRunning = false;
        };
        
        while (MainClass.keepRunning) {
            // Do your work in here, in small chunks.
            // If you literally just want to wait until Ctrl+C,
            // not doing anything, see the answer using set-reset events.
        }
        Console.WriteLine("exited gracefully");
    }
}

La diferencia entre este código y el primer ejemplo es que e.Cancelse establece en verdadero, lo que significa que la ejecución continúa después del delegado. Si se ejecuta, el programa espera a que el usuario presione Ctrl+ C. Cuando eso sucede, la keepRunningvariable cambia de valor, lo que hace que salga el ciclo while. Esta es una forma de hacer que el programa salga correctamente.

Jonas avatar May 30 '2009 13:05 Jonas

Ver MSDN:

Evento Console.CancelKeyPress

Artículo con ejemplos de código:

Ctrl-C y la aplicación de consola .NET

aku avatar Oct 07 '2008 10:10 aku

Me gustaría agregar algo a la respuesta de Jonas . Girar en a boolprovocará una utilización del 100% de la CPU y desperdiciará mucha energía sin hacer nada mientras se espera CTRL+ C.

La mejor solución es utilizar a ManualResetEventpara "esperar" el CTRL+ C:

static void Main(string[] args) {
    var exitEvent = new ManualResetEvent(false);

    Console.CancelKeyPress += (sender, eventArgs) => {
                                  eventArgs.Cancel = true;
                                  exitEvent.Set();
                              };

    var server = new MyServer();     // example
    server.Run();

    exitEvent.WaitOne();
    server.Stop();
}
Jonathon Reinhart avatar Dec 16 '2012 07:12 Jonathon Reinhart

Aquí hay un ejemplo de trabajo completo. pegar en el proyecto de consola C# vacío:

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..");
        }
    }
}
JJ_Coder4Hire avatar Apr 10 '2014 18:04 JJ_Coder4Hire