Click here to Skip to main content
Click here to Skip to main content

Console Event Handling

By , 29 May 2002
 

Introduction

Everyone programs console applications one time or the other. This programming is more prevalent when people are learning to program, especially while learning the DOS based C/C++ programming. However, when one migrates to Windows programming, console application development takes a back seat. But the Win32 console development holds an important place, especially when the Win32 API contains a good amount of API dedicated to console application development. If you have noticed, even VC++, and latest development technologies like C#, also supports console project development. Console applications are good candidates for testing the core functionality of your Windows application without the unnecessary overhead of a GUI.

But there's always been a sense of helplessness in regard to how to know when certain system related events have occurred, like when user if logging off, or the system is being shutdown, or handling control+break or control+C keyboard events, etc. For a Windows based application, getting to know when such events occur is no problem since they are having a message queue assigned to them that is polled, and assuming that the concerned event is programmed for, it can be handled pretty easily. But this isn't the case with a console application that has no concept of a message queue.

This article intends to discuss how you can handle all kinds of console-based events in any console application. Once you have gone through it, you will see for yourself how trivial this seemingly helpless task is :)

Setting Console Traps

The first step in handling console application events is to setup an even trap, technically referred to as installing an event handler. For this purpose, we utilize the SetConsoleCtrlHandler Win32 API that is prototyped as shown below:

BOOL SetConsoleCtrlHandler(
    PHANDLER_ROUTINE HandlerRoutine, // handler function
    BOOL Add // add or remove handler
    );

The HandlerRoutine parameter is a pointer to a function that has the following prototype:

BOOL WINAPI HandlerRoutine(
    DWORD dwCtrlType   //  control signal type
);

All the HandlerRoutine takes is a DWORD parameter that tells what console event has taken place. The parameter can take the following values:

  • CTRL_C_EVENT - occurs when the user presses CTRL+C, or when it is sent by the GenerateConsoleCtrlEvent API.
  • CTRL_BREAK_EVENT - occurs when the user presses CTRL+BREAK, or when it is sent by the GenerateConsoleCtrlEvent API.
  • CTRL_CLOSE_EVENT - occurs when attempt is made to close the console, when the system sends the close signal to all processes associated with a given console.
  • CTRL_LOGOFF_EVENT - occurs when the user is logging off. One cannot determine, however, which user is logging off.
  • CTRL_SHUTDOWN_EVENT - occurs when the system is being shutdown, and is typically sent to services.

Upon receiving the event, the HandlerRoutine can either choose to do some processing, or ignore the event. If the routine chooses not to handle the event, it should return FALSE, and the system shall then proceed to the next installed handler. But incase the routine does handle the event, it should then return TRUE, after doing all the processing it requires. The CTRL_CLOSE_EVENT, CTRL_LOGOFF_EVENT and CTRL_SHUTDOWN_EVENT are typically used to perform any cleanup that is required by the application, and then call the ExitProcess API. Thus, the system has has some timeouts associated with these three events, which is 5 seconds for CTRL_CLOSE_EVENT, and 20 seconds for the other two. If the process doesn't respond within the timeout period, Windows shall then proceed to display the End Task dialog box to the user. If the user proceeds to end the task, then the application will not have any opportunity to perform cleanup. Thus, any cleanup that is required should complete well within the timeout period. Below is an exemplification of the handler routine:

BOOL WINAPI ConsoleHandler(DWORD CEvent)
{
    char mesg[128];

    switch(CEvent)
    {
    case CTRL_C_EVENT:
        MessageBox(NULL,
            "CTRL+C received!","CEvent",MB_OK);
        break;
    case CTRL_BREAK_EVENT:
        MessageBox(NULL,
            "CTRL+BREAK received!","CEvent",MB_OK);
        break;
    case CTRL_CLOSE_EVENT:
        MessageBox(NULL,
            "Program being closed!","CEvent",MB_OK);
        break;
    case CTRL_LOGOFF_EVENT:
        MessageBox(NULL,
            "User is logging off!","CEvent",MB_OK);
        break;
    case CTRL_SHUTDOWN_EVENT:
        MessageBox(NULL,
            "User is logging off!","CEvent",MB_OK);
        break;

    }
    return TRUE;
}

Now that we have seen how the handler routine works, lets see how to install the handler. To do so, as mentioned earlier in the article, we use the SetConsoleCtrlHandler API as shown below:

if (SetConsoleCtrlHandler(
    (PHANDLER_ROUTINE)ConsoleHandler,TRUE)==FALSE)
{
    // unable to install handler... 
    // display message to the user
    printf("Unable to install handler!\n");
    return -1;
}

The first parameter is a function pointer of the type PHANDLER_ROUTINE, whose prototype has been discussed earlier. The second parameter, if set to TRUE, tries installing the handler, and if set to FALSE, attempts the un-installation. If either attempts are successful, the return value is TRUE. Otherwise FALSE is returned.

So, that's all there is to handling the console application events. After handler is installed, your application will receive the events as and by they come, and when the execution is about to be terminated, the handler maybe un-installed. Pretty easy, eh :) ?

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Kumar Gaurav Khanna
Web Developer
United States United States
Member
I hold Early Acheiver in MCSE 2000, MCSE NT 4.0, MCP+I, and actively involved in programming using C/C++, .NET framework, C#, Win32 API, VB, ASP and MFC.
 
I also have various publications to my credit at MSDN Online Peer Journal, Windows Developer Journal (http://www.wdj.com/), Developer 2.0 (http://www.developer2.com/), and PC Quest (http://www.pcquest.com/).

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralDoes not work anymore with Windows 7 [modified]memberFrederic Sivignon10 Jun '11 - 4:27 
Still works fine with Vista (32/64), but no more with Windows 7.
Incredible regression...
 
Causing the same issue for Java code implementation used to detect JVM shutdown event: Does not
work anymore under Windows 7.
 
Meaning that plenty of applications, well coded to nicely release resources before a shutdown, won't work now.
 

 
Still not find an acceptable solution for that. D'Oh! | :doh:
 
[EDIT] Oppss... There is a simple solution: Microsoft.Win32.SystemEvents class. Works fine under Seven too.

modified on Friday, June 10, 2011 12:11 PM

GeneralLock computermemberDeepak Kumar Singh7 Dec '04 - 2:04 
Hi!
 
Good article. In case we want to handle the event of user locking the computer (Ctl+Alt+DEL then 'Lock Computer') then how do we do that? Lets say my application is a windows service!
 
Thanks,
Deepak

GeneralRe: Lock computermemberDeepak Kumar Singh7 Dec '04 - 19:13 
Hi!
 
I got the answer my self. Unless you are really working with console based applications, you should rather work with 'Winlogon Notification Packages'. But they are not supported on Win NT and lower.
 
For more info see:
 
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/secauthn/security/winlogon_notification_packages.asp[^]
 
-- Deepak
GeneralNice, but ...sussAnonymous9 Apr '03 - 15:12 
it only works if a console window exists. If you use it within a gui application, you won't receive any messages. Furthermore it does not work with Win95/98 and WinME. Or did anyone made other experiences?

GeneralMessageBoxmemberSarwan Aggarwal27 Aug '03 - 16:18 
Hi:
 
I like that MessageBox example code:
 
int MessageBox(0, char *msg, char *title, int type);
 
Which header do I include? My VC++ 6.0 does not recognize
MessageBox().
 
Thanks.
 
Sarwan
 
Sarwan K. Aggarwal
GeneralRe: MessageBoxmemberyjip14 Nov '03 - 23:26 
you can look msdn ,that there are information sdk very much!
if you not see ,you can keep in touch with me my emailaddress : 4915259@163.com
ok
 
yjip
GeneralRe: MessageBoxmemberyathirajkulal11 Jan '11 - 18:45 
U should add Windows.h
GeneralRe: Nice, but ...memberToal Ber G. Iron1 Feb '13 - 20:53 
And who said this is for gui applications?
QuestionHow can I pass control-break to console application?memberSlimer30 Mar '03 - 22:42 
How can I pass control-break to console application?
GeneralArgh!sussAnonymous18 Feb '03 - 19:34 

Alright, the author mentions that when the program is about to be closed, the handler is unisntalled... This may have something to do with an issue I'm having...
 
I have a program that uses AllocConsole() to get a console. Most of the entire program is all WinAPI, and the console is only used for quickly adding large amounts of data. So I launch my app, it spawns a console, the console is made into a child window... Now, if you click close, the whole app goes down. Ctrl-C and the same...
 
I installed an insane amount of message handlers before learning about the Console Control Handler. (Duh!)... Now that I'm using the control handler to try and trap the events, the Ctrl-C problem is taken care of. But no matter what, whenever you close it, the whole program goes down. How do you stop this? I'd prefer the console just get freed instead of killing the whole app!
Dead | X|
GeneralRe: Argh!sussAnonymous3 May '04 - 23:58 
in each of the console event handlers, you could call FreeConsole(),
This seemed to work for me, the only thing was there was a slight delay between the close button being clicked and the console window being destroyed.
Questionhow can i get the source code!sussAnonymous14 Nov '02 - 22:26 
This is a wonderful article but how can I get the source code. I download it but I can not unzip it.Kindly send me the code. Thanks.
AnswerSameple code Re: how can i get the source code!memberSMuddasu15 Nov '02 - 8:29 
BOOL CtrlHandler(DWORD fdwCtrlType)
{
switch (fdwCtrlType)
{
// Handle the CTRL+C signal.

case CTRL_C_EVENT:

Beep(1000, 1000);
return TRUE;

// CTRL+CLOSE: confirm that the user wants to exit.

case CTRL_CLOSE_EVENT:

return TRUE;

// Pass other signals to the next handler.

case CTRL_BREAK_EVENT:

case CTRL_LOGOFF_EVENT:

case CTRL_SHUTDOWN_EVENT:

default:

return FALSE;
}
}

void main(void)
{
BOOL fSuccess;

fSuccess = SetConsoleCtrlHandler(
(PHANDLER_ROUTINE) CtrlHandler, // handler function
TRUE); // add to list
if (! fSuccess)
cout << "Could not set control handler");
}

 
Sagar
GeneralRe: Sameple code Re: how can i get the source code!memberXkirill13 Jul '09 - 3:30 
can you translate it to VB please?
QuestionWhere is the Source gone?membersilliconXP31 May '02 - 17:14 
This is a very good posting.it can even be better with the source code.kindly to send me.

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web03 | 2.6.130523.1 | Last Updated 30 May 2002
Article Copyright 2002 by Kumar Gaurav Khanna
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid