Cómo atrapo ctrl-c en una aplicación de consola C #

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

Ver MSDN:

Evento Console.CancelKeyPress

Artículo con muestras de código:

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

El evento Console.CancelKeyPress se usa para esto. 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 + C, se ejecuta el código en el delegado y el progtwig sale. Esto le permite realizar la limpieza llamando a los métodos necesarios. Tenga en cuenta que no se ejecuta código después de que el delegado.

Hay otras situaciones donde esto no lo reducirá. Por ejemplo, si el progtwig está realizando cálculos importantes que no se pueden detener de inmediato. En ese caso, la estrategia correcta podría ser decirle al progtwig que salga después de que se complete el cálculo. El siguiente código proporciona un ejemplo de cómo esto se puede implementar:

 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.Cancel se establece en verdadero, lo que significa que la ejecución continúa después del delegado. Si se ejecuta, el progtwig espera a que el usuario presione Ctrl + C. Cuando eso sucede, la variable keepRunning cambia el valor que hace que el ciclo while salga. Esta es una forma de hacer que el progtwig salga con gracia.

Me gustaría agregar a la respuesta de Jonas . Girar en un bool causará un 100% de utilización de la CPU, y perderá un montón de energía haciendo una gran cantidad de nada mientras espera CTRL + C.

La mejor solución es usar un ManualResetEvent para realmente “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(); } 

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

 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.."); } } } 

Esta pregunta es muy similar a:

Captura la salida de la consola C #

Así es como resolví este problema, y ​​lidié con el usuario que golpeaba la X y también Ctrl-C. Observe el uso de ManualResetEvents. Esto hará que el hilo principal se suspenda, lo que libera a la CPU para procesar otros hilos mientras espera la salida o la limpieza. NOTA: es necesario configurar TerminationCompletedEvent al final de main. De lo contrario, se produce una latencia innecesaria en la finalización debido a que el sistema operativo agota el tiempo de espera mientras se elimina la aplicación.

 namespace CancelSample { using System; using System.Threading; using System.Runtime.InteropServices; internal class Program { ///  /// Adds or removes an application-defined HandlerRoutine function from the list of handler functions for the calling process ///  /// A pointer to the application-defined HandlerRoutine function to be added or removed. This parameter can be NULL. /// If this parameter is TRUE, the handler is added; if it is FALSE, the handler is removed. /// If the function succeeds, the return value is true. [DllImport("Kernel32")] private static extern bool SetConsoleCtrlHandler(ConsoleCloseHandler handler, bool add); ///  /// The console close handler delegate. ///  ///  /// The close reason. ///  ///  /// True if cleanup is complete, false to run other registered close handlers. ///  private delegate bool ConsoleCloseHandler(int closeReason); ///  /// Event set when the process is terminated. ///  private static readonly ManualResetEvent TerminationRequestedEvent; ///  /// Event set when the process terminates. ///  private static readonly ManualResetEvent TerminationCompletedEvent; ///  /// Static constructor ///  static Program() { // Do this initialization here to avoid polluting Main() with it // also this is a great place to initialize multiple static // variables. TerminationRequestedEvent = new ManualResetEvent(false); TerminationCompletedEvent = new ManualResetEvent(false); SetConsoleCtrlHandler(OnConsoleCloseEvent, true); } ///  /// The main console entry point. ///  /// The commandline arguments. private static void Main(string[] args) { // Wait for the termination event while (!TerminationRequestedEvent.WaitOne(0)) { // Something to do while waiting Console.WriteLine("Work"); } // Sleep until termination TerminationRequestedEvent.WaitOne(); // Print a message which represents the operation Console.WriteLine("Cleanup"); // Set this to terminate immediately (if not set, the OS will // eventually kill the process) TerminationCompletedEvent.Set(); } ///  /// Method called when the user presses Ctrl-C ///  /// The close reason private static bool OnConsoleCloseEvent(int reason) { // Signal termination TerminationRequestedEvent.Set(); // Wait for cleanup TerminationCompletedEvent.WaitOne(); // Don't run other handlers, just exit. return true; } } } 

Console.TreatControlCAsInput = true; me ha funcionado