如何使控制台应用程序在关闭时正常退出

时间:2014-02-13 10:29:48

标签: c# .net winapi

我写了这个小程序来证明问题的重点:

using System;
using System.IO;
using System.Threading;

class Program
{
    static void Main(string[] args)
    {
        using (var disp = new MyDisp())
        {
            using (var ewhLocalExit = new EventWaitHandle(false, EventResetMode.ManualReset))
            {
                Console.WriteLine("Enter Ctrl+C to terminate the app.");
                Console.CancelKeyPress += (_, e) =>
                {
                    e.Cancel = true;
                    ewhLocalExit.Set();
                };
                ewhLocalExit.WaitOne();
            }
        }
        File.AppendAllText("Log.txt", "Terminated.\n");
    }
}


class MyDisp : IDisposable
{
    public MyDisp()
    {
        File.AppendAllText("Log.txt", "Started.\n");
    }

    public void Dispose()
    {
        File.AppendAllText("Log.txt", "Disposed.\n");
    }
}

当我运行它并按Ctrl + C时,我看到“Started.Disposed.Terminated”。在Log.txt中 当我运行它并用鼠标关闭它时,我只看到“已启动”。

如何优雅地退出,这样我至少可以看到“Disposed”。 ?

2 个答案:

答案 0 :(得分:2)

当您通过单击X按钮关闭控制台应用程序时,您要求让该进程终止。

Wi32 api有SetConsoleControlHandler,允许您指定处理各种事件的处理程序。如果使用CTRL_CLOSE_EVENT调用处理程序,那么您就知道有人试图杀死您的应用程序。

有一个如何使用此API here

的示例

答案 1 :(得分:2)

您可以使用DLLImport导入SetConsoleControlHandler并使用它为已关闭的事件(和其他人)注册事件处理程序,这是一个显示它正常工作的示例代码段(当您单击X时,它将在Log.txt中写入关闭关闭控制台):

class Program
{
    [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
    }

    private static bool ConsoleCtrlCheck(CtrlTypes ctrlType)
    {
        if (ctrlType == CtrlTypes.CTRL_CLOSE_EVENT)
            File.AppendAllText(@"Log.txt", "closed");

        return true;
    }

    private static void Main(string[] args)
    {
        SetConsoleCtrlHandler(new HandlerRoutine(ConsoleCtrlCheck), true);
        Console.WriteLine("Close me");
        Console.ReadLine();
    }
}

Source