【问题标题】:SetConsoleCtrlHandler routine issueSetConsoleCtrlHandler 例程问题
【发布时间】:2011-04-08 03:00:36
【问题描述】:

我正在用 C++ 编写一个控制台应用程序。

我使用 SetConsoleCtrlHandler 来捕获关闭和 CTRL+C 按钮。这允许我的所有线程正确停止和退出。

其中一个线程执行了一些需要一些时间才能完成的保存操作,并且我在控制台 crtl 处理例程中有一些代码要等待。 MSDN 指定 CTRL_CLOSE_EVENT 5 秒后应弹出一个框,但我的进程退出了。

这对于调试控制台应用程序也很烦人,因为进程在您可以单步执行之前就退出了,我不知道可能是什么问题(我有 Windows 7 64 位)。

另外,奇怪的是,如果我的例程返回 TRUE(简单地禁用关闭操作),它仍然会关闭应用程序。该例程确实被调用,因此 SetConsoleCtrlHandler 安装成功。

例如:

BOOL WINAPI ConsoleHandlerRoutine(DWORD dwCtrlType)
{
    if (dwCtrlType == CTRL_CLOSE_EVENT)
    {
        return TRUE;
    }

    return FALSE;
}

int _tmain(int argc, _TCHAR* argv[])
{
    BOOL ret = SetConsoleCtrlHandler(ConsoleHandlerRoutine, TRUE);

    while (true)
    {
        Sleep(1000);
    }
    return 0;
}

有什么想法吗?

【问题讨论】:

    标签: c++ windows console-application


    【解决方案1】:

    您似乎无法再忽略 Windows 7 上的关闭请求。

    确实收到了 CTRL_CLOSE_EVENT 事件,从那一刻起,您有 10 秒的时间在它自动关闭之前做任何您需要做的事情。所以你可以在处理程序中做任何你需要做的工作,或者设置一个全局标志。

    case CTRL_CLOSE_EVENT: // CTRL-CLOSE: confirm that the user wants to exit.
                           close_flag = 1;
                           while(close_flag != 2)
                             Sleep(100);
                           return TRUE;
    

    有趣的事实:当 CTRL_CLOSE_EVENT 事件中的代码运行时,主程序继续运行。因此,您将能够检查标志并执行“close_flag = 2;”某处。但请记住,您只有 10 秒。 (因此请记住,例如,您不想挂起等待键盘输入的主程序流程。)

    【讨论】:

    • 10 秒时间只是事实的一半。一旦处理程序返回,应用程序将被终止,因此您必须保持处理程序运行。
    • 请注意,处理程序是在任意线程的上下文中运行的(这就是程序继续运行的原因)。因此,您应该使用一些线程安全机制来表示终止正在进行中(例如事件)。
    • 如果处理程序返回 false 并调用默认处理程序,则进程通过ExitProcess(STATUS_CONTROL_C_EXIT) 退出。如果进程在返回之前自行退出,它可以使用不同的退出代码来指示成功关闭。否则,如果处理程序返回 true 或花费超过 5 秒(不是 10 秒),进程将被会话服务器 (csrss.exe) 强制终止,退出代码为 STATUS_CONTROL_C_EXIT
    【解决方案2】:

    我怀疑这是 Windows 7 的设计使然 - 如果用户想要退出您的应用程序,您不能告诉他“不”。

    【讨论】:

    • 同意。以前显示的对话框是 gonzo。
    【解决方案3】:

    无需等待主线程的任何标志,一旦主线程退出(或10s后),处理程序就会终止。

    BOOL WINAPI ConsoleHandler(DWORD dwType)
    {
        switch(dwType) {
        case CTRL_CLOSE_EVENT:
        case CTRL_LOGOFF_EVENT:
        case CTRL_SHUTDOWN_EVENT:
    
          set_done();//signal the main thread to terminate
    
          //Returning would make the process exit!
          //We just make the handler sleep until the main thread exits,
          //or until the maximum execution time for this handler is reached.
          Sleep(10000);
    
          return TRUE;
        default:
          break;
        }
        return FALSE;
    }
    

    【讨论】:

      【解决方案4】:

      Xavier 的评论略有错误。 Windows 7 允许您的代码在事件处理程序中大约 10 秒。如果您在 10 秒内没有退出事件处理程序,您将被终止。如果您退出事件处理程序,您将立即终止。返回 TRUE 不会发布对话框。它只是退出。

      【讨论】:

        【解决方案5】:

        你让这变得比它需要的更复杂。我不知道你的应用关闭的确切原因,但SetConsoleCtrlHandler(NULL, TRUE) 应该做你想做的事:

        http://msdn.microsoft.com/en-us/library/ms686016(VS.85).aspx

        如果 HandlerRoutine 参数为 NULL,TRUE 值导致调用进程忽略 CTRL+C 输入,FALSE 值恢复正常处理 CTRL+C 输入。

        【讨论】:

        • 当我按下控制台上的关闭按钮时仍然退出。 CTRL+C 不是问题,因为这也可以解决问题: if (dwCtrlType == CTRL_C_EVENT) return TRUE;导致我出现问题的是关闭按钮。
        猜你喜欢
        • 2021-12-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-10-29
        • 1970-01-01
        相关资源
        最近更新 更多