阻止c#控制台应用程序退出的最终代码[直到自定义清理代码完成]

时间:2012-09-22 10:09:28

标签: c# .net console-application shutdown resource-cleanup

我们可以合作提出适用于control-c,control-break,注销,按下窗口X按钮等的东西吗?

这是我到目前为止所做的:

class Program
{  
    private static ConsoleEventHandlerDelegate consoleHandler;
    delegate bool ConsoleEventHandlerDelegate(CtrlTypes eventCode);

    static void Main(string[] args)
    {
        consoleHandler = new ConsoleEventHandlerDelegate(ConsoleCtrlCheck);
        SetConsoleCtrlHandler(consoleHandler, true);

        System.Diagnostics.Process.GetCurrentProcess().Exited 
           += delegate(object sender, EventArgs e) 
        {              
            GeneralManager.Stop();
        };

        Console.CancelKeyPress += delegate(object sender,
                                ConsoleCancelEventArgs e)
        {
            e.Cancel = false;
            GeneralManager.Stop();
        };

        GeneralManager.Start();
    }

    private static bool ConsoleCtrlCheck(CtrlTypes ctrlType)
    {
        switch (ctrlType)
        {                
            case CtrlTypes.CTRL_C_EVENT:

                Console.WriteLine("CTRL+C received!");
                GeneralManager.Stop();
                break;

            case CtrlTypes.CTRL_BREAK_EVENT:
                isclosing = true;
                Console.WriteLine("CTRL+BREAK received!");
                GeneralManager.Stop();
                break;

            case CtrlTypes.CTRL_CLOSE_EVENT:

                Console.WriteLine("Program being closed!");
                GeneralManager.Stop();
                break;

            case CtrlTypes.CTRL_LOGOFF_EVENT:
            case CtrlTypes.CTRL_SHUTDOWN_EVENT:

                Console.WriteLine("User is logging off!");
                GeneralManager.Stop();
                break;                           
        }
        return true;
    }

    #region unmanaged

            [DllImport("kernel32.dll")]
          static extern bool SetConsoleCtrlHandler(ConsoleEventHandlerDelegate
            handlerProc, bool add);

    public delegate bool HandlerRoutine(CtrlTypes CtrlType);

    public enum CtrlTypes
    {
        CTRL_C_EVENT = 0,
        CTRL_BREAK_EVENT,
        CTRL_CLOSE_EVENT,
        CTRL_LOGOFF_EVENT = 5,
        CTRL_SHUTDOWN_EVENT
    }

    #endregion
}

两个问题:

  1. 在Managed Control-Break处理程序中,如果我们设置e.Cancel = true,它会因.Net4的异常而失败。这在MSDN文章中有说明,没有解决方法:http://msdn.microsoft.com/en-us/library/system.consolecanceleventargs.cancel.aspx

  2. 我不知道如何取消ConsoleCtrlCheck中的关闭。我得到一两次清理,但我宁愿取消并确保一切正常完成。

  3. 更新

    感谢您的回复。两者都赞成。将等待,看看是否有人能够提出直接解决我要求的回复,否则将接受其中一个“使用NT服务”的答案。

1 个答案:

答案 0 :(得分:0)

我花了几个小时看这个,因为我现在没有时间建立一个有效的代码;虽然它可能很短,但正确的做法需要一段时间。我只是给你链接到完成这项工作所需的各种东西:

http://pastebin.com/EzX3ezrf

总结粘贴代码中的经验教训:

  1. 需要一个消息泵来处理部分/全部WM_QUERYENDSESSION,WM_ENDSESSION,CTRL_SHUTDOWN_EVENT(在c#SystemEvents.SessionEnding中可能涵盖部分/全部)

  2. 获取消息泵的最简单方法是使其成为隐藏的表单/窗口应用程序,但我记得可以构建为控制台应用程序并添加消息泵。我没有在粘贴中包含该代码。

  3. “如果应用程序必须阻止潜在的系统关闭,它可以调用ShutdownBlockReasonCreate函数”

  4. 由于AllocConsole用于创建控制台,您需要使用SetConsoleCtrlHandler并在处理程序中使用ExitThread(1)。这是一个“黑客”,可以杀死关闭控制台的线程。它在FarManager中使用。例如,参见interf.cpp

  5. 使用AllocConsole时,还需要初始化和清理控制台。

  6. 据报道按CTRL + C会搞砸输入。我不确定FarManager是否正在处理这种情况。 interf.cpp中的CTRL_BREAK_EVENT处理程序中有一些代码,我不确定它是做什么的。

  7. FarManager还处理WM_POWERBROADCAST,可能与暂停

  8. 有关

    如果所有这些都不够(应该是),您还可以将控制台添加到另一个进程中并将您的消息IPC添加到此处,如此处所示。 Why does closing a console that was started with AllocConsole cause my whole application to exit? Can I change this behavior?

    RMTool可用于模拟用于测试的注销/关闭消息:http://download.microsoft.com/download/d/2/5/d2522ce4-a441-459d-8302-be8f3321823c/LogoToolsv1.0.msi

    MSDN在microsoft.win32.systemevents.sessionending.aspx上也有一些C#代码 和microsoft.win32.systemevents.aspx(隐藏形式示例)

    mischel.com/pubs/consoledotnet/consoledotnet.zip有一个示例winTest项目,正在使用AllocConsole并处理了一些事件。