捕获控制台出口C#

Zer*_*vin 88 .net c# console events exit

我有一个包含很多线程的控制台应用程序.有些线程可以监视某些条件,如果它们是真的则终止程序.这种终止可以随时发生.

我需要一个可以在程序关闭时触发的事件,以便我可以清理所有其他线程并正确关闭所有文件句柄和连接.我不确定.NET框架中是否已经内置了一个,所以我在编写自己的框架之前就已经问过了.

我想知道是否有一个事件:

MyConsoleProgram.OnExit += CleanupBeforeExit;
Run Code Online (Sandbox Code Playgroud)

flq*_*flq 92

我不确定我在网上找到代码的位置,但我现在在我的一个旧项目中找到了它.这将允许您在控制台中执行清理代码,例如,当它突然关闭或由于关闭时...

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


static void Main(string[] args)
{
  // Some biolerplate to react to close window event
  _handler += new EventHandler(Handler);
  SetConsoleCtrlHandler(_handler, true);
  ...
}
Run Code Online (Sandbox Code Playgroud)

更新

对于那些没有检查评论的人来说,似乎这个特定的解决方案在Windows 7上运行不佳(或根本没有).以下主题讨论了这一点

  • 这在Windows 7(64位)上对我很有用.不知道为什么每个人都说不.我做的唯一主要修改是摆脱enum和switch语句,并从方法中"返回false" - 我在方法体中做了我所有的清理工作. (10认同)
  • 这很好用,只有`bool Handler()`必须`返回false;`(它在代码中什么都不返回)所以它会起作用.如果返回true,则Windows会提示"立即终止处理"对话框.= d (7认同)
  • 你能用它取消退出吗?除了当它关闭时! (4认同)
  • 看起来此解决方案不适用于Windows 7 for shutdown事件,请参阅http://social.msdn.microsoft.com/Forums/en/windowscompatibility/thread/abf09824-4e4c-4f2c-ae1e-5981f06c9c6e (3认同)
  • 请注意,如果在"Handler"方法中放置断点,则会抛出NullReferenceException.检查VS2010,Windows 7. (3认同)
  • 请参阅http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/545f1768-8038-4f7a-9177-060913d6872f/和http://www.pinvoke.net/default.aspx/kernel32. CreateToolHelp32Snapshot函数 (2认同)

JJ_*_*ire 25

完整的工作示例,使用ctrl-c,用X关闭窗口并杀死:

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 boilerplate 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..");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 我在 Windows 7 上测试了这个,除了 `return true` 和一个计算秒数的 while 循环之外,所有的东西都从 `Handler` 中注释掉了。应用程序继续按 ctrl-c 运行,但在使用 X 关闭时会在 5 秒后关闭。 (3认同)
  • 在 Windows 10 上,我可以在窗口上按 CTRL-C、X,并在任务管理器中结束进程。 (2认同)

jms*_*era 8

检查还:

AppDomain.CurrentDomain.ProcessExit
Run Code Online (Sandbox Code Playgroud)

  • 这只会出现从return或Environment.Exit中捕获退出,它不会捕获CTRL + C,CTRL + Break,也不会捕获控制台上的实际关闭按钮. (7认同)
  • @RobinHartmann 我已经重新测试了这一点,并且得到了相同的结果 - https://repl.it/@Konard/CultivatedForsakenQueryoptimizer 这是两个单独的事件,并且在 `CancelKeyPress` 事件之后触发 `ProcessExit` 事件。 (2认同)

Joã*_*ela 5

我遇到了类似的问题,只是我的控制台应用程序将在无限循环中运行,中间有一个抢占式语句。这是我的解决方案:

class Program
{
    static int Main(string[] args)
    {
        // Init Code...
        Console.CancelKeyPress += Console_CancelKeyPress;  // Register the function to cancel event

        // I do my stuffs

        while ( true )
        {
            // Code ....
            SomePreemptiveCall();  // The loop stucks here wating function to return
            // Code ...
        }
        return 0;  // Never comes here, but...
    }

    static void Console_CancelKeyPress(object sender, ConsoleCancelEventArgs e)
    {
        Console.WriteLine("Exiting");
        // Termitate what I have to terminate
        Environment.Exit(-1);
    }
}
Run Code Online (Sandbox Code Playgroud)