5

In windows console application, one can catch pressing ctrl+c by using:

#include <stdio.h>
#include <signal.h>

void SigInt_Handler(int n_signal)
{
    printf("interrupted\n");
}

int main(int n_arg_num, const char **p_arg_list)
{
    signal(SIGINT, &SigInt_Handler);
    getchar(); // wait for user intervention
}

This works well, except it does not work at all if the user presses the cross × that closes the console window. Is there any signal for that?

The reason I need this is I have this CUDA application which tends to crash the computer if closed while computing something. The code is kind of multiplatform so I'd prefer using signals rather than SetConsoleCtrlHandler. Is there a way?

the swine
  • 10,713
  • 7
  • 58
  • 100

1 Answers1

5

The correct one is SIGBREAK, you can try it with:

#include <stdio.h>
#include <signal.h>

void SigInt_Handler(int n_signal)
{
    printf("interrupted\n");
    exit(1);
}

void SigBreak_Handler(int n_signal)
{
    printf("closed\n");
    exit(2);
}

int main(int n_arg_num, const char **p_arg_list)
{
    signal(SIGINT, &SigInt_Handler);
    signal(SIGBREAK, &SigBreak_Handler);
    getchar(); // wait for user intervention
    return 0;
}

Upon closing the console window, the program will print "closed" and will return 2.

the swine
  • 10,713
  • 7
  • 58
  • 100
  • Isn't it so, though, that you cannot abort the exit at that point? It seems there is now to prevent the console from exiting when inside the handler. – Ruud van Gaal Jan 18 '17 at 12:59
  • 1
    You could wait forever I guess, upon which a "Force close" dialog would pop up. But since there is no return value, I guess you cannot abort. I just wanted a way to delay the exit and shutdown the application properly. – the swine Jan 27 '17 at 15:31
  • @theswine, in Vista and later there's no dialog. If the control handler returns `TRUE` or takes longer than 5 seconds to return, Windows (csrss.exe) forcibly terminates the process. If the handler returns `FALSE`, the default handler calls `ExitProcess`. In these cases the process exit code is `STATUS_CONTROL_C_EXIT` (0xC000013A). – Eryk Sun Sep 06 '17 at 17:23
  • The C runtime's console control handler raises `SIGINT` for `CTRL_C_EVENT` and `SIGBREAK` for all others, including `CTRL_CLOSE_EVENT`. – Eryk Sun Sep 06 '17 at 17:25
  • Is there a way to actually send these different signals to the console application, for instance to check if the signal handlers are working properly? On NIX you can do this to some extend with the `kill` command. For instance taskkill on Windows can only do a hard kill on console applications. – Yunus King Mar 01 '19 at 11:02
  • @ArisKoning Have not tried. I imagine if you handle the event, it should be caught first, even if you send it programatically. See https://stackoverflow.com/a/1179124/1140976. – the swine Mar 12 '19 at 23:44
  • 1
    In Windows 10 this no longer works, the signal handler installed with `SIGBREAK` is never called and the app exits immediatelly. – Youda008 Nov 23 '19 at 19:43
  • @Youda008 Thanks for the update! Any other handlers that get called in 10? – the swine Dec 02 '19 at 22:12
  • I have no idea, i had to use `SetConsoleCtrlHandler` and ruin the cross-platformness. – Youda008 Dec 04 '19 at 13:43
  • 1
    @Youda008, no, the `SIGBREAK` handler is called in Windows 10 for `CTRL_BREAK_EVENT` and `CTRL_CLOSE_EVENT`, even under Windows Terminal. The only cases where it has ever been a bit wonky are for the console's `CTRL_LOGOFF_EVENT` and `CTRL_SHUTDOWN_EVENT`. They're sent and mapped to `SIGBREAK` for a simple console application. However they aren't sent if the process loads user32.dll (i.e. if the process is attached to a window station and desktop). It's expected that an app that's connected to the desktop session will create a window and handle `WM_QUERYENDSESSION` and `WM_ENDSESSION`. – Eryk Sun Sep 30 '20 at 08:09