SetConsoleCtrlHandler routine issue

2019-04-03 09:59发布

问题:

I'm writting a console application in C++.

I use SetConsoleCtrlHandler to trap close and CTRL+C button. This allows for all my threads to stop and exit properly.

One of the thread performs some saving that require some time to complete and I have some code to wait in the console crtl handle routine. MSDN specify that a box should pop up after 5 seconds for CTRL_CLOSE_EVENT, but instead my process exits.

This is annoying for debugging console application too as the process exits before you can step through and I don't know what may be the problem (I have Windows 7 64bits).

Also, strangely if my routine returns TRUE (to simply disable the close action), it still closes the application. The routine does get called, so the SetConsoleCtrlHandler was successful installed.

e.g.:

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;
}

Any ideas?

回答1:

It looks like you can no longer ignore close requests on Windows 7.

You do get the CTRL_CLOSE_EVENT event though, and from that moment on, you get 10 seconds to do whatever you need to do before it auto-closes. So you can either do whatever work you need to do in the handler or set a global flag.

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

Fun fact: While the code in your CTRL_CLOSE_EVENT event runs, the main program keeps on running. So you'll be able to check for the flag and do a 'close_flag = 2;' somewhere. But remember, you only have 10 seconds. (So keep in mind you don't want to hang up your main program flow waiting on keyboard input for example.)



回答2:

I suspect that this is by-design on Windows 7 - if the user wants to quit your application, you're not allowed to tell him "No".



回答3:

There is no need to wait for any flag from the main thread, the handler terminates as soon as the main thread exits (or after 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's comment is slightly wrong. Windows 7 allows your code in the event handler ~10 seconds. If you haven't exited the event handler in 10 seconds you are terminated. If you exit the event handler you are terminated immediately. Returning TRUE does not post a dialog. It just exits.



回答5:

You're making this more complicated than it needs to be. I don't know exactly why your app is closing, but SetConsoleCtrlHandler(NULL, TRUE) should do what you want:

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

If the HandlerRoutine parameter is NULL, a TRUE value causes the calling process to ignore CTRL+C input, and a FALSE value restores normal processing of CTRL+C input.