1

Windows 10, C++. I have a graphic app which opens a console, writes a few things, and waits until user clicks the close on the console. I only want for console to close, but the entire app exits. Yes, the handler is entered. I also see that this was an issue more than 10 years ago. So, is there another way around this?

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

The handler is defined as follows.

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

    default: return FALSE;
    }
}
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • possible duplicate of https://stackoverflow.com/questions/11959643/why-does-closing-a-console-that-was-started-with-allocconsole-cause-my-whole-app – Cody Gray - on strike Nov 20 '21 at 16:14
  • Indeed. Briefly, as soon as one clicks the x to close the console, Windows (subsystems) begin cleaning up and preparing to exit. A few centuries later, it invokes the handler merely to see if you want to do some more cleanup. At that point, the only action is to end the process. Thus, the documentation is misleading when it says, returning true no further handlers are invoked. It appears to be saying, the signal will be ignored. That is not true. – Sohrab Honargohar Nov 21 '21 at 15:21
  • I didn't mark this as a duplicate, because I have an answer on the Q&A that I proposed, which would make me voting to close it a possible conflict-of-interest. However, I will point out that I have to deal with this exact same issue in a production application. My workaround is to disable the close ("X") button in the titlebar for the console while my application is running so the user *can't* click it. This must be done *very* carefully, though, to ensure that the close button can't be left disabled when the app crashes. I use RAII in C++ to ensure that is not possible. – Cody Gray - on strike Nov 21 '21 at 15:36
  • Thanks. That will not work for me. I want user to actually close the console. In short, the main app (an IDE) may be asked to run (the release version of) some other app, which may be a console or a GUI app. The way I solved this is to sense what type of app it is, and somehow make it either call main(), or WinMain(). before calling CreateProcess(). The sensing is complicated to explain, but I use the argument for that purpose (in the context I am working). The technique cannot be used for general purpose, so I am not mentioning it here. – Sohrab Honargohar Nov 21 '21 at 21:07
  • In that case, I would agree with Remy Lebeau's comment that you should make the app always be a Windows app (with a WinMain entry point). This does not automatically display any user interface, so it is suitable for both a UI app *and* a "headless" one. If you want a console window, then just call `AllocConsole` from within WinMain. By so doing, you free your app from getting forcibly closed whenever the console window is closed, because it is running in its own context. – Cody Gray - on strike Nov 23 '21 at 06:24
  • Oh, thanks. But I already solved the problem in the context I am working. It works great. In my context, in the string "Program.exe argument" that is passed to CreateProcess(), the "Program.exe" is not arbitrary. So, I have two versions of it, one starting with main(), the other with WinMain(). This can be decided from flags I add to "argument". That is not usable for general purpose. However, your comment should be helpful for others. Thanks though. – Sohrab Honargohar Nov 23 '21 at 23:56

1 Answers1

0

No matter which value your handler returns, Windows is going to kill your process after your or the last handler returns.

  • If your process is going to shut down soon after receiving this signal, notify your application to start shutting down and then sleep/wait forever in the handler.

  • If you want your application to continue to run as normal, you could perhaps call ExitThread(1337); in your handler. This is a giant hack and who knows if it works on all Windows versions.

If neither of the two methods are acceptable then I'm afraid you might have to use a child process as the console owner.

Anders
  • 97,548
  • 12
  • 110
  • 164
  • Exiting the controller thread will cause problems. For instance, if you kill the thread, and then try to call `AllocConsole()` again later, it could lock up, or even crash. – Remy Lebeau Nov 20 '21 at 05:37
  • 1
    A better design is to simply not use the console at all. The app is a GUI app, so create your own UI to display console-like output as needed. – Remy Lebeau Nov 20 '21 at 05:38
  • Thank you for clean and direct answers. I will try the UI as a workaround. However, the whole idea of a handler is to be able to ignore the signal (in this context). Too bad it does not work, and now I know not to continue on this path. Thanks. – Sohrab Honargohar Nov 20 '21 at 13:39