检测控制台退出事件

时间:2015-12-03 13:45:32

标签: c#

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

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

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

3 个答案:

答案 0 :(得分:3)

看看这个例子,它运行正常:

主要

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

答案 1 :(得分:1)

  return false;

这不符合你的期望。您无法取消关闭请求,返回值仅告诉Windows是否应该调用任何其他注册的处理程序。因此,无论您返回true还是false都不会影响结果,操作系统将始终终止该程序。

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

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

答案 2 :(得分:1)

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

Console.CancelKeyPress += Console_CancelKeyPress;

在此之前做事情

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

希望这是你想要做的。