3

我知道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);

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

4

3 回答 3

7

的文档SetConsoleCtrlHandler()说:

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

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

于 2009-02-10T18:17:32.057 回答
1

实际上你可以阻止它(我至少在 Windows XP 上复制了它)。例如,如果在您的处理程序中,您有一个无限循环和睡眠,这将阻止该进程永远终止(或至少很长时间,或直到用户通过任务管理器终止该进程)。

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

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

于 2012-07-14T03:36:09.523 回答
1

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

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

编辑:这似乎确实会导致一些问题,正如我所料。随后对 AllocConsole() 的调用无限期挂起,因此我怀疑过早退出线程无法正确清理。

编辑2:

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

大多数情况下,我认为,这些问题将与控制台 API 有关。如前所述,AllocConsole从此时起无法工作(它将挂起应用程序),因此程序无法打开新控制台。其他控制台功能也很可能会失败。基本上,从那时起,您以任何方式(直接或间接)调用 kernel32 的任何操作都会受到未定义行为的影响,但我怀疑实际上在控制台功能之外不会有任何问题。

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

于 2013-08-26T13:14:05.033 回答