【问题标题】:Is there a workaround for SetConsoleCtrlHandler() issue?SetConsoleCtrlHandler() 问题是否有解决方法?
【发布时间】:2021-12-30 15:57:27
【问题描述】:

Windows 10,C++。我有一个图形应用程序,它打开一个控制台,写一些东西,然后等到用户点击控制台上的关闭。我只想让控制台关闭,但整个应用程序都会退出。是的,处理程序已输入。我还看到这是 10 多年前的一个问题。那么,有没有其他方法可以解决这个问题?

// Graphic app makes following calls
...
AllocConsole();
SetConsoleCtrlHandler(ConsoleCloseHandler, TRUE);
...

处理程序定义如下。

BOOL WINAPI ConsoleCloseHandler(DWORD signalType) {
    switch (signalType) {
    case CTRL_CLOSE_EVENT:
    case CTRL_C_EVENT:
        FreeConsole();
        return TRUE;

    default: return FALSE;
    }
}

【问题讨论】:

  • 确实如此。简而言之,只要单击 x 关闭控制台,Windows(子系统)就会开始清理并准备退出。几个世纪后,它调用处理程序只是为了查看您是否想做更多的清理工作。此时,唯一的行动就是结束该过程。因此,当文档说返回 true 时不会调用进一步的处理程序时,它会产生误导。似乎是在说,信号将被忽略。这不是真的。
  • 我没有将此标记为重复,因为我对我提出的问答有一个答案,这将使我投票结束它可能存在利益冲突。但是,我要指出,我必须在生产应用程序中处理这个完全相同的问题。我的解决方法是在我的应用程序运行时禁用控制台标题栏中的关闭(“X”)按钮,以便用户无法单击它。但是,这必须非常小心地完成,以确保在应用程序崩溃时关闭按钮不会被禁用。我在 C++ 中使用 RAII 来确保这是不可能的。
  • 谢谢。那对我不起作用。我希望用户真正关闭控制台。简而言之,可能会要求主应用程序(IDE)运行(发布版本)一些其他应用程序,这些应用程序可能是控制台或 GUI 应用程序。我解决这个问题的方法是感知它是什么类型的应用程序,并以某种方式使其调用 main() 或 WinMain()。在调用 CreateProcess() 之前。感觉解释起来很复杂,但我为此目的使用了这个论点(在我正在工作的上下文中)。该技术不能用于通用目的,所以我在这里不提。
  • 在这种情况下,我同意 Remy Lebeau 的评论,即您应该使应用程序始终是 Windows 应用程序(具有 WinMain 入口点)。这不会自动显示任何用户界面,因此它适用于 UI 应用“无头”应用。如果你想要一个控制台窗口,那么只需在 WinMain 中调用AllocConsole。这样一来,您的应用就不会在控制台窗口关闭时被强制关闭,因为它是在自己的上下文中运行的。

标签: c++ windows winapi console


【解决方案1】:

无论您的处理程序返回哪个值,Windows 都会在您或最后一个处理程序返回后终止您的进程。

  • 如果您的进程在收到此信号后很快将关闭,请通知您的应用程序开始关闭,然后在处理程序中永远休眠/等待。

  • 如果您希望您的应用程序继续正常运行,您可以在处理程序中调用ExitThread(1337);。这是一个巨大的 hack,谁知道它是否适用于所有 Windows 版本。

如果这两种方法都不可接受,那么恐怕您可能不得不使用子进程作为控制台所有者。

【讨论】:

  • 退出控制器线程会出问题。例如,如果你杀死线程,然后再次尝试调用AllocConsole(),它可能会锁定,甚至崩溃。
  • 更好的设计是根本不使用控制台。该应用程序是一个 GUI 应用程序,因此请创建您自己的 UI 以根据需要显示类似控制台的输出。
  • 感谢您干净直接的回答。我将尝试使用 UI 作为解决方法。但是,处理程序的整个想法是能够忽略信号(在这种情况下)。太糟糕了,它不起作用,现在我知道不要继续走这条路了。谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-04-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-28
  • 2023-04-06
  • 1970-01-01
相关资源
最近更新 更多