如何使用SetConsoleHandler()来阻止退出调用

时间:2009-02-10 18:11:44

标签: c# console exit

我知道如果我想管理控制台关闭事件,我必须使用setconsolehandler()

我不知道如何阻止CTRL_CLOSE_EVENT。如果它捕获了那个事件,我尝试返回false / true,但没有成功

这是我到目前为止(感谢Anton Gogolev!)

[DllImport("Kernel32")]
public static extern bool SetConsoleCtrlHandler(HandlerRoutine Handler, 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
}

private static bool ConsoleCtrlCheck(CtrlTypes ctrlType)
{ 
    if(ctrlType == CtrlTypes.CTRL_CLOSE_EVENT)
        return false;// I have tried true and false and viceversa with the return   
                     // true/false but I cant seem to get it right.
    return true;
}


//and then I use this to call it
SetConsoleCtrlHandler(new HandlerRoutine(ConsoleCtrlCheck), true);

还可以运行一个新线程来监视控制台是否正在关闭,如果主线程正在做某事,可以阻止关闭吗?

3 个答案:

答案 0 :(得分:6)

SetConsoleCtrlHandler()的文档说:

  

当用户关闭控制台,注销或关闭系统时,系统会生成CTRL_CLOSE_EVENT,CTRL_LOGOFF_EVENT和CTRL_SHUTDOWN_EVENT信号,以便该进程有机会在终止前进行清理。

这意味着与处理CTRL + C或CTRL + BREAK事件不同,您的进程无法取消关闭,注销或关闭。

答案 1 :(得分:1)

实际上你可以阻止它(我至少在Windows XP上重现了这个)。例如,如果在你的处理程序中你有一个无休止的while循环,那么这将阻止这个过程永远终止(或者至少很长一段时间,或者直到用户通过任务管理器终止进程)。

如果你真的需要启动一个线程,你可以使用等待条件(C#中的AutoResetEvent)并启动你的线程(虽然在大多数情况下可能不需要新线程)然后通知等待条件当你的线程完成。但是,在大多数情况下,只需在处理程序中进行任何清理就足够了。

如果在最糟糕的情况下你确实等待了,那么这个过程将继续运行,当你重新登录时(至少在Windows XP上),你将能够看到它。但是,这会导致桌面在进入注销屏幕之前暂停约20秒(当它等待您的应用程序退出时),然后在注销屏幕再次暂停(我想它第二次尝试时) 。当然,我强烈建议不要永远等待;对于任何长期运行的东西,你应该把它放在服务中。

答案 2 :(得分:1)

我发现了一个可能会阻止应用程序关闭的'hack',同时仍然整齐地遵守控制台关闭请求。 特别是,我认为这适用于将控制台创建为“额外”的GUI应用程序。 从MSDN文档中,在调用Ctrl处理程序的位置,在进程中创建新线程以调用处理程序。我的解决方案是在默认处理程序可以调用ExitProcess之前杀死攻击的入侵线程。在处理程序例程中(C ++中的代码):

// Detach Console:
FreeConsole();
// Prevent closing:
ExitThread(0);
return TRUE; // Not reached

编辑:看来这确实会引起一些问题,我想是可以预料到的。随后对AllocConsole()的调用无限期挂起,因此我怀疑过早退出该线程无法正常清理。

编辑2:

为了澄清上述内容,我发现继续运行该程序没有直接问题。但请记住,我们已经强制终止了kernel32创建的线程,因此kernel32中的任何资源都可能处于不确定状态。当程序继续运行时,这可能会导致无法预料的问题。

大多数情况下,我认为,这些问题与Console API有关。如上所述,AllocConsole从此时起无法工作(它会挂起应用程序),因此程序无法打开新的控制台。其他控制台功能很可能也会失败。基本上,从那一点起你做的任何事情(直接或间接)调用kernel32都会受到不确定的行为的影响,但我怀疑在实践中不会出现Console函数之外的任何问题。

我的结论是,如果可能的话,你应该避免使用这种方法,但是如果提前终止更糟,那么这可以被认为是一种紧急的解决办法,可以谨慎而小心地使用。

相关问题