Search code examples
c++linuxwindowsconsoleatexit

Trap exit on console


I would like to call a cleanup function after the user presses the small "x" at the top right hand corner of the console window.

I have registered an atexit method but this doesn't get called in this case.

Solution needs to work on windows and linux.


Solution

  • You cannot use atexit here because, it is called when a process is terminated normally, whereas in your case the process is terminated by a signal.

    On linux, SIGHUP (signal hang up) is sent to the process when its controlling terminal is closed, and you can use POSIX signal handling.

    On windows, CTRL_CLOSE_EVENT event is delivered, and you can use SetConsoleCtrlHandler winapi to handle this.

    So, to my knowledge, there's no platform independent way to handle this in c++. You should use platform dependent code to do this as shown in the following simple program. I tested it on windows with VS and on ubuntu with g++. Please note that error handling has been omitted and I/O is performed in signal handlers for simplicity.

    The program registers a signal handler and an atexit function. Then it sleeps for 10 seconds. If you do not close the console within 10s, the process will terminate normally and the atexit handler will be called. If you close the window before 10s, it'll catch the signal. On linux, you won't see the signal handler getting called, but it does get called, you can check this by writing a file (or issuing a beep?), though I don't recommend it.

    #ifdef  WIN32
    #include <windows.h> 
    #else
    #include <unistd.h>
    #include <signal.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #endif
    
    #include <stdio.h>
    #include <stdlib.h>
    
    
    #ifdef  WIN32
    BOOL sig_handler(DWORD signum) 
    { 
        switch( signum ) 
        { 
            case CTRL_CLOSE_EVENT: 
                printf( "Ctrl-Close event\n" );
                return( TRUE ); 
    
            default: 
                return FALSE; 
        } 
    }
    #else
    void sig_handler(int signum)
    {
        /* you won't see this printed, but it runs */
        printf("Received signal %d\n", signum);
    }
    #endif 
    
    
    void exit_fn(void)
    {
       printf("%s\n", __FUNCTION__);
    }
    
    
    void setup_signal_handler()
    {
    #ifdef  WIN32
        SetConsoleCtrlHandler((PHANDLER_ROUTINE)sig_handler, TRUE);
    #else
        struct sigaction sa;
        sa.sa_handler = &sig_handler;
        sigfillset(&sa.sa_mask);
        sigaction(SIGHUP, &sa, NULL);
    #endif  
    }
    
    
    int main(void)
    {
        printf("%s\n", __FUNCTION__);
        /* setup signal handler */
        setup_signal_handler();
        /* setup function to be called at normal process termination */
        atexit(exit_fn);
        /* sleep for 10s */
    #ifdef  WIN32
        Sleep(10000);
    #else
        sleep(10);
    #endif
        /* print message if process terminates normally */
        printf("Normal process termination\n");
    
        exit(EXIT_SUCCESS);
    }