Super TRACE

One of the nice utilities that MFC provides the developers with is the "tracing" utility.  This allows you to mark up any section of the code so that it would print a string message to the debug output window using the OutputDebugString API function.  You can use trace in your application like this:

void my_function( void )
{
TRACE( _T("entering my_function( )") );
// do some work here
TRACE( _T("exiting my_function( )") );
}

Also, it’s possible to use the TRACE macro in a more advanced way to use the printf-like string formatting:

void my_param_function( LPCTSTR string, int number, float flt )
{
TRACE( _T("my_param_function( %s, %d, %f );"), string, number, flt );
// ...
}

The TRACE macro is especially useful when debugging multithreaded code, in which setting breakpoints or using MessageBox’s or other means of checking some value inside a function would change the normal flow of the threads in the program.

There are four varieties of the TRACE macro, names TRACE0, TRACE1, TRACE2, and TRACE3.  They’re the same as TRACE, where as TRACE0 only takes a string parameter, TRACE1 takes one parameter other than the format string parameter, and so on.  So, as an example, the above my_param_function( ) can be written with TRACE3 as well.  Of course, because TRACE0, TRACE1, TRACE2, and TRACE3 wrap the first string parameters inside a _T macro for Unicode compatibility, you should not put the first strings inside a _T, but the other possible strings should be wrapped inside a _T macro.  So, here’s another version of my_param_function:

void my_param_function( LPCTSTR string, int number, float flt )
{
TRACE3( "my_param_function( %s, %d, %f );", string, number, flt );
// ...
}

Now, we’ll come to a negative point in the TRACE macros.  When you watch the debug output window, you see the trace messages, but the only way you have to recognize exactly which part of the code is generating a certain message is to do a "Find in Files" in Visual C++.  This problem shows itself more when you consider you’re debugging a project with, let’s say, 1000 TRACE statements.  Here the Super TRACE macros come in handy.  To use the Super TRACE macros, all you need is to include the header file supertrc.h after including either afx.h or afxwin.h.  Now, all of your normal TRACE, TRACE0, TRACE1, TRACE2, and TRACE3 macros will be changed to Super TRACE macros, which let’s you easily double-click on the trace message in the debug output window to navigate to the exact file and line of the code that has generated the trace messages.  The download link to supertrc.h header file can be found at the end of the article.

MFC itself uses trace macros internally a lot.  A nice feature of Super TRACE is you can force MFC also to print the file names and line numbers of the code that generates the trace message.  But unfortunately, to obtain such a feature, the only way is recompiling the MFC source code (distributed with Visual C++).  In case you’re interested in having Super TRACE in the MFC library itself (and I encourage you to do so) open the stdafx.h file inside the MFC source directory, and add an #include statement for supertrc.h after the include line for afx.h like this:

// ...
// core headers
#include "afx.h"
/*** Super TRACE ***/
#include "supertrc.h"
#include "afxplex_.h"
#include "afxcoll.h"
// ...

And then build the MFC library using the make files provided.

 Download source code for this article

This article originally appeared on BeginThread.com. It’s been republished here, and may contain modifications from the original article.

Posted in Visual C++