检测控制台退出事件

本文关键字:出事件 退出 控制台 检测 | 更新日期: 2023-09-27 18:25:26

我创建了一个控制台应用程序,它有一个将kinect流存储到硬盘的方法。我想捕获控制台退出事件以关闭kinect流,因为当控制台退出关闭事件时我会遇到问题。我想找到一种方法来检测控制台的退出事件。我遇到了如下的解决方案。我将以下代码添加到我的应用程序中:

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

并且在主要功能:

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

我首先在思考是否可以将处理程序事件导入到布尔变量,其次如何将其作为程序构造函数的输入来关闭流。

编辑:我的程序构造函数:

public Program(string filePath)
    {
        Thread thread = new Thread(() => writeRGSStream(file));
        thread.Start();
        writeSkelFiles(file);
    }

我想在writeRGSStream方法中输入标志。我可以打吗

SetConsoleCtrlHandler(new HandlerRoutine(ConsoleCtrlCheck), true);

在该方法内部以获取标志值?

检测控制台退出事件

看看这个例子,它工作得很好:

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

控制台检查

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

和WinAPI部分:

#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

使用CancelKeyPress事件(在CTRL+C上激发)。

Console.CancelKeyPress += Console_CancelKeyPress;

在关闭之前做一些事情

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

希望这就是你想要做的。

  return false;

这并没有达到你所希望的效果。您不能取消关闭请求,返回值只是告诉Windows它是否应该调用任何其他注册的处理程序。因此,无论您返回true还是false都不会影响结果,操作系统总是会终止程序。

因此,您需要做的任何事情都必须在回调方法中完成。小心你的选择非常有限。毕竟,你的主线程正忙于写入该文件,你无法删除它。这也不是一个真正的解决方案,如果你的应用程序因任何其他原因终止,你仍然会遇到麻烦。就像未处理的异常一样,用户用任务管理器杀死它,或者有人被电源线绊倒并拔下机器。

只需编写更智能的代码,使用临时名称创建文件,并在完成编写后重命名文件。现在,您永远不在乎程序因任何原因而中断。