How to Trap, Ctrl+C, Break, Close events in your console application?

 

imageBy default, the console applications break (stop execution) when user Press, Ctrl+C button, or close by pressing “Close button” in the title bar.

In the post, I’m explaining about how to trap these events in your console application. SetConsoleCtrlHandler function can be used to set the handles for Ctrl+Events.

Function is prototyped as follows.

BOOL WINAPI SetConsoleCtrlHandler(
__in_opt PHANDLER_ROUTINE HandlerRoutine,
__in BOOL Add );

The HandlerRoutine can be a local function in your application and should match with the HandlerRoutine prototype. The Add parameter determines whether the callback to add or removed.

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. This attribute of ignoring or processing CTRL+C is inherited by child processes.

If a console process is being debugged and CTRL+C signals have not been disabled, the system generates a DBG_CONTROL_C exception. This exception is raised only for the benefit of the debugger, and an application should never use an exception handler to deal with it

More information on this API is detailed in MSDN documentation.

The following describes how to define a control hander routine and how it can be used. In this sample application exits only by pressing “Close” button of the console window.

[sourcecode language='cpp']
#include

using namespace std;

bool gExit = false; // flag to exit from while loop
// Handler callback
BOOL WINAPI TrapCtrlHandler( DWORD dwCtrlType )
{
switch( dwCtrlType )
{
case CTRL_C_EVENT:
cout << “Processing Ctrl+C event\n” << endl ;
break;

case CTRL_CLOSE_EVENT:
cout << “Processing Ctrl+Close event\n” << endl ;
gExit = true; // Set to exit process
break;

case CTRL_BREAK_EVENT:
cout << “Ctrl-Break event” << endl;
break;

default:
return FALSE; // unhandled.Some other in the call back list can process
}
return TRUE; // handled the events
}

void main()
{
if( SetConsoleCtrlHandler( TrapCtrlHandler, TRUE ))
{
cout << “The Control Handler is installed.” << endl;
while( !gExit );
}
else
cout << “ERROR: Could not set control handler”;
}
[/sourcecode]

 

How to convert a STL container to array

 

Most of the collection classes in C# and Java provides interface to pack the data as an array but C++ STL containers like vector, list etc. are not having direct interface to do this.

To accomplish this, you can write a simple function as follows which is exploiting the power of std::copy function. The function specified below is compatible with any containers which supports iterators. i.e you can use, vector, list etc. with this function. (If you’ve a better idea, please share through comments).

template<class T, class container >
bool ToArray( const container& vec, T*& pArrayOut  )
{
    int cnt = vec.size();
    if( cnt > 0)
    {
        pArrayOut = new T[cnt];
        copy(vec.begin(),vec.end(), pArrayOut );
        return true;
    }
    else
    {
        pArrayOut = NULL;
        return false;
    }
}


The pointer should be freed by the caller using delete[] operator. The reason for specifying the output pointer as function argument is to support calling template function without type information. Which means, if the function specified as T* ToArray( const container& ), you can call it as ToArray<int>(vec). You will have to specify the type of the function, but if it’s a parameter, the compiler will automatically deduce the function type.
The following code describes, how to use the function

int _tmain(int argc, _TCHAR* argv[])
{
    list<int> v; // you can also use <vector>  instead of list
    v.push_back( 10 );
    v.push_back( 20 );
    v.push_back( 40 );
    v.push_back( 50 );
    v.push_back( 1220 );
    v.push_back( 1320 );

    int* t  =  ToArray(v, t );
    if( NULL != t )
    {
        cout << "Failed to convert";

        for( int i =0; i < v.size();i++ )
        {
            cout << t[i] << "\t" ;
        }
        delete []t; // free after use
    }
    return 0;
}
 

How to write your own trace function?

 

Most of us are using TRACE, ATLTRACE macros, OuputDebugString API for  debugging purpose during our development. [Go to end and check the function if you don't want to hear more about the basics of debug strings] Debug strings are used for debugging purpose and it’s displayed by debugger during debugging. You can see it in the output window of most of the debuggers (especially in Visual Studio) and also some smart utilities like DbgView captures the system wide debugging string and it displays in it’s own window without debugging any of the process.

Mainly OutputDebugString function provided by Kernel32 DLL is used for “outputing” debug strings. There are other altenatives available like TRACE, ATLTRACE2 macros, afxDump function etc. and most of these are actually wrapping OutputDebugString API and provides flavored functionalities like formatting like printf string, dumping MFC objects etc. The most widely used are TRACE macros. There are some more alternatives for TRACE macros like TRACE0, TRACE1, TRACE2 (deprecated now). It’s nothing but impossing restrictions on the number of parameters.

Trace macros are supposed to work with debug build of the applciation and in release mode, the traces will not be available. If we approach OutputDebugString API, we will have to first format string using sprintf or CString::Format function and then pass to API. But this adds the burden of declaring temporary buffer/CString objects every time we call this function as follows

[sourcecode language='cpp']
CString csMessage;
csMessage.Format(_T(“My Data:%d”), nData );
OutputDebugString(csMessage).
[/sourcecode]

You will always have to repeat the above code wherever you need a debug trace. Ofcourse TRACE macro can be used as printf like function, but only in debug mode. So it’s better to write our own trace functions. 

The following function is  variadic function which can be used as printf function with format specifierss

[sourcecode language='cpp']
void M4DTrace( LPCTSTR lpctFormat, … )
{
static TCHAR szBuffer[1000];
va_list ArgList;
va_start( ArgList, lpctFormat );
_vstprintf_s( szBuffer, lpctFormat, ArgList );
va_end( ArgList );
OutputDebugString( szBuffer );
}
[/sourcecode]

Instead of _vsntprintf_s, you can use another formating function called wvsprintf
but I found it has some problems formatting float variables in the list. The above function can runs under both UNICODE and MBCS environment.
If you need to know under the hood of OutputDebugString, please check this article
Updated[2009-Apr-17) – updated formatting with _vstprintf_s instead of _vsntprintf_s

 

Proudly powered by WordPress
Theme: Esquire by Matthew Buchanan.