2

I build the following program in VS2017/Windows 10. When I run it, I hit close and ctrl_handler() is called as expected, but after ~three seconds the process is forcefully terminated anyway.

This is a problem because my real application writes large log files and three seconds is not long enough to get them onto disk.

Where is the documentation that describes this behaviour? Its not in those for the CTRL+CLOSE signal.

Where is the timeout set? Can it be modified at the application level? Or with a group policy?

#include <Windows.h>

bool mainThreadRunning;
bool mainThreadFinished;

BOOL ctrl_handler(DWORD event)
{
    if (event == CTRL_CLOSE_EVENT) {
        mainThreadRunning = false;
        while (!mainThreadFinished) {
            Sleep(100);
        }
        return TRUE;
    }
    return FALSE;
}

int main()
{
    mainThreadRunning = true;
    mainThreadFinished = false;

    SetConsoleCtrlHandler((PHANDLER_ROUTINE)(ctrl_handler), TRUE);  // make sure when the user hits the close button in the console we shut down cleanly

    while (true)
    {

    }

    return 0;
}
Roman R.
  • 68,205
  • 6
  • 94
  • 158
sebf
  • 2,831
  • 5
  • 32
  • 50
  • 2
    To send a control event, the console host (conhost.exe) requests the session server (csrss.exe) to create a control thread in the client. This thread starts at `kernelbase!CtrlRoutine` and calls the registered handlers until either a handler returns `TRUE` or it gets to the default handler (`kernelbase!DefaultHandler`) that calls `ExitProcess(STATUS_CONTROL_C_EXIT)`. Vista and later do not allow a handler to keep the process (and console) alive by returning true for the close event. Instead the session server waits for 5 seconds and terminates the process if it hasn't exited. – Eryk Sun Oct 31 '17 at 23:49

1 Answers1

3

I suppose this is the reference you were looking for:

Unfortunately, this is determined by the OS. There is documentation describing the behavior in the HandlerRoutine Callback docs:

" In this case, no other handler functions are called, and the system displays a pop-up dialog box that asks the user whether to terminate the process. The system also displays this dialog box if the process does not respond within a certain time-out period (5 seconds for CTRL_CLOSE_EVENT, and 20 seconds for CTRL_LOGOFF_EVENT or CTRL_SHUTDOWN_EVENT)."

There is no (at least public, documented) API to change this timeout.

Note:

A process can use the SetProcessShutdownParameters function to prevent the system from displaying a dialog box to the user during logoff or shutdown. In this case,the system terminates the process when HandlerRoutine returns TRUE or when the time-out period elapses.

The operating system intentionally forces termination if it considers handler is taking too much time to complete.

Important note pulled from comments below:

... Ctrl+C is not subject to the time-out (I've tested it, and that's what I am using now).

Community
  • 1
  • 1
Roman R.
  • 68,205
  • 6
  • 94
  • 158
  • 2
    The pop-up dialog for the close event is pre-Vista behavior, in which an application could keep the console alive by returning true for the close event. This was eliminated in Vista. When the user closes the window (or gracefully kills the process the console reports as its effective owner, which sends `WM_CLOSE` to the console window), all processes attached to the console at the time can either exit or be terminated. No one gets a vote on the matter. A process can't even detach from the console to stay alive, since the session server already has it marked for death. – Eryk Sun Nov 01 '17 at 00:08
  • 1
    Thanks, that does seem to be all MS intends to say about the subject! I like (not) how the thread quotes a timeout that MS has since removed from the documentation, as if they are trying to obfuscate it. ~ For interests sake, since its ambiguously written, CTRL_C is not subject to the time-out (I've tested it, and that's what I am using now). – sebf Nov 01 '17 at 12:55
  • 1
    @sebf, it's typical to also use Ctrl+Break because it cannot be ignored, unlike Ctrl+C. For example, a program can call `GenerateConsoleCtrlEvent` to send a Ctrl+C or Ctrl+Break to either all processes attached to the console (including itself) or a process group that was created with the `CreateProcess` flag `CREATE_NEW_PROCESS_GROUP` (CMD's `start /B` uses this flag). This can gracefully kill a process group. But the lead process of a group is created with Ctrl+C ignored. It could manually re-enable it via `SetConsoleCtrlHandler(NULL, False)`, but that's not something a caller can control. – Eryk Sun Nov 01 '17 at 16:27