Currently viewing: GipsySoft » Front Page» Articles

Debug Helper

[Why use DebugHlp]   [How to Use DebugHlp]   [Download and Installation]   [Reference]

This project provides some essential debug helper functions and macros based on those available with MFC and the C runtime but with some handy extensions. I use it in all of my projects and it's use has saved me countless hours of debugging.

Why Use DebugHlp.

I like my code to be as robust as possible, to shout out whenever I call a function incorrectly, I want as much help avoiding bugs possible. Assertions in your code assure you that your program is healthy, DebugHlp provides assertions, trace output and other helpful macros.

DebugHlp adds several new ideas to the standard MFC and runtime assertions and trace output.

  • The filename and line number of the trace statement is output as well as the trace text, this means that when a trace statement is viewed in the Microsoft Visual C++ debugger you can simply double click on the text in the output window to go to the exact source line of the trace statement.
  • ASSERT also puts the expression in the Abort, Retry, Ignore dialog box. The MFC ASSERT does not. The runtime version does but when you Retry it dumps you in the assertion code not yours - you need to crawl up the stack to get to your code. DebugHlp is the best of both.
  • When an assert fails the expression is traced out. This means you can Ignore the assertion failures knowing that the line and filename of the offending ASSERT has been recorded in the output window for future investigation. Plus it can be copied straight into a bug report.
  • Handy VERIFY extension will also display the error code and the matching error string, no more guessing why an API failed. Includes being copied to the output window.
  • Extra assertions to assert the validity of a HWND, whether a string is valid and whether a pointer is readable/writable.
  • Can write every trace message and assertion failure to a TSV (tab seperated values) log file, complete with date and time of the event.

If you code using API and you like using ASSERTs and VERIFYs then DebugHlp will lighten the load. If you use MFC then DebugHlp adds some welcome extensions.

Why Assert anything.

Asserting that your code is valid at any given point is valuable because it ensures consitency. Saying that a pointer cannot be NULL, or that certain values are invalid informs callers of your code without having to understand why. Adding comments to your assertions goes one step further by giving reasons why the code was designed to handle certain parameters.

If you want to know more about assertions then I recommend you read Writing Solid Code.

[TOP]

Download and Installation.

Once the zip file has been extracted you can simply copy the LIB, DLL and header files to your usual library, executable and include directories and start using it. However, I use a particular project layout structure that you may find useful, you can read about it here, I would recommend you give it a try.

The Zip file consists of all of the source code required to build the DLL and LIB. You can download it and start using immediately because I have also included a release compile which includes the DLL and LIB files.

Click to download DebugHlp now! — 24KB

[TOP]

How to Use DebugHlp.

Once the files and paths are setup and ready to use you can start making use of DebugHlp by including the DebugHlp.h file in your main pre-compiled header file:

	#include <DebugHlp.h>

The library will be automatically linked if you are using Microsoft Visual C++, if not then you may need to add DebugHlp.lib in the library/objects list for you linker - standard stuff for using any library.

When using MFC be sure to include DebugHlp.h after the MFC header files in your stdafx.h.

[TOP]

Reference.

SETLOGFILE( filename )

Parameters
filename The path of the file that will contain the trace output

Remarks

If you don't use SETLOGFILE then no log file is written. If you do then every trace message (including assertion failures) will be written to the file specifed

The format of the written file is:


<date><tab><time><tab><message>

By including the date and time you can track a lot of interesting things in your application including rough execution times.

 

ASSERT( exp )

Parameters
exp the expression you would like to test

Remarks

Evaluate the expression passed and generate a debug report when the result of the expression is FALSE. The debug report consists of a dialog box with three buttons, Abort, Retry and Ignore. Abort will terminate the program, Ignore will behave as if the expression had had evaluated TRUE and Retry will interrupt the program and allow you to debug it at the point of the assertion.

 

TRACE( exp )

Parameters
exp printf style variable arguments with formatting

The output from TRACE goes directly to the output window of the debugger. Additionally, the filename and line number are output to enable easy location of trace statements.

	RECT rc;
	GetWindowRect( hwnd, &rc );
	TRACE("Width(%d Height(%d)\n", rc.right - rc.left, rc.bottom - rc.top );

 

STOPHERE()

Remarks

STOPHERE simply places _asm { int 3 } instruction in the code, this is similar to DebugBreak() except that it places the debugger right at the source code rather than in a function call. No need to navigate the stack back a level to see your code.

To use it simply drop it into your source code. It's even used in ASSERT and VAPI

	STOPHERE();

 

VERIFY( exp )

Parameters
exp the expression you would like to test

Similar to ASSERT but the expression remains in the code even in release. This is useful when you want to assert the return value of a function but don't mind if the function fails in release. This is generally used for early warnings. In the following example the VERIFY will fail if the bitmap m_hBitmap cannot be deleted, e.g. if the bitmap is still selected into a DC.

	VERIFY( ::DeleteObject( m_hBitmap ) );

 

VAPI( exp )

Parameters
exp the expression you would like to test

Similar to VERIFY except VAPI is used only for API functions that can fail. If the expression evaluates to FALSE then an ASSERT style dialog box is displayed with the addition of the error number and relevant message returned by ::GetLastError().

	VAPI( ::GetWindowRect( (HWND)1234, NULL ) );

The above code will generate a dialog box similar to the following, notice that the expression is the same as that used in the VAPI statement and that the error number and the system error string are also displayed.

 

ASSERT_VALID_HWND( hwnd )

Parameters
hwnd the window handle you would like to assert on.

If the window handle passed is invalid then you will get an assertion failure. Useful for validating the parameters passed to functions. ASSERT_VALID_HWND uses ::IsWindow() to check the window handle and not just tests the window handle against NULL.

 

ASSERT_VALID_STR_LEN( str, n )
ASSERT_VALID_STR( str )

Parameters
str pointer to a C-style string
n length of the string in characters

If the string passed is not valid, that is the string cannot be read up to n bytes or until the strings terminating null character then you will get an assertion failure dialog box. Useful for validating the parameters passed to functions.

The following code demonstrates the use of ASSERT_VALID_STRING and also ASSERT_VALID_WRITEPTR. The first assertion will fire if psz is not a valid string and the second assertion will fire if the string is not writable. This will be the case if the example code is compiled using Visual C++ 6.0 or a compiler that moves constant strings into read-only memory.

void ValidWriteString( LPTSTR psz )
{
	//	Should be a valid string pointer
	ASSERT_VALID_STR( psz );
	ASSERT_VALID_WRITEPTR( psz, lstrlen( psz ) );
}

void main()
{
	ValidWriteString( _T("Some text in read-only memory") );
}

 

ASSERT_VALID_WRITEPTR( obj, n )
ASSERT_VALID_WRITEOBJPTR( obj )

Parameters
obj pointer to an object
n size of the object in bytes

If you attempt to pass a pointer to memory that you do not have write permission for you get an assertion failure dialog box. Useful for asserting that parameters to functions are valid pointers.

ASSERT_VALID_READPTR( obj, n )
ASSERT_VALID_READOBJPTR( obj )

Parameters
obj pointer to an object
n size of the object in bytes

If you attempt to pass a pointer to memory that you do not have read permission for you will get an assertion failure dialog box. Useful for asserting that parameters to functions are valid pointers.

The code below shows a typical use for the ASSERT_VALID_WRITEPTR, the assertion will fire if prc does not point to an area of memory the size of a RECT that is writable.

void ValidWritePointer( LPRECT prc )
{
	//	Should be a valid rect pointer
	ASSERT_VALID_WRITEPTR( prc, sizeof( RECT ) );
}

[TOP]