Here is some Win32 error handling/reporting code. While it's not game
programming specific, hopefully it will be of some use.  Feel free to use this
code in any way you would like.

[Editor's Note: submitted as a COTD by Josh Harler [jharler@hotmail.com]]

/**************************************************************************//*!
 * Include files needed for the following functions:
 *     windows.h - needed for everything windows.
 *     eh.h      - needed for exception handling.
 *
 * The first function is useful for getting a textual error message when a
 * Win32 API function fails.  The next two functions are used for handling
 * exceptions in your program.
 *
 * String is my own string class.  This should be replaced by your favorite
 * string class.
 *
 * In case you're wondering, the comments are formatted the way they are for
 * documentation with doxygen.
 */


/**************************************************************************//*!
 * Used to determine what Win32 error occurred.  When a Win32 API function
 * call fails, use this function to extract a textual error message from
 * Windows.
 *
 * \returns The string describing the Win32 error that occurred.
 */
	String win32_SystemError( void )
	{
		LPTSTR szMsgBuf;

		DWORD dwErr = GetLastError();
		if( dwErr == 0 )
			return "";	// no error

		FormatMessage(
			FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
			NULL,
			dwErr,
			MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ),
			(LPTSTR) &szMsgBuf,
			0,
			NULL );

		String sMsg( szMsgBuf );
		LocalFree( szMsgBuf );
		return sMsg.Left( sMsg.Length() - 1 );	// eliminate the newline char
	}


/**************************************************************************//*!
 * Initializes the exception handling.  This should be called at the very
 * beginning of your program.
 * 
 */
	void win32_InitException( void )
	{
		_set_se_translator( win32_Exception );
	}

/**************************************************************************//*!
 * Handles exceptions.  This will be called by Windows whenever an exception
 * occurs in your program.  It is called from your program before the
 * exception is actually thrown.  
 *
 * Error is my own error handling class that logs the error to file.  This
 * function is particularly useful if you have a logging method that reports
 * what function you are in (such as the logging code from Paul Nettle,
 * another COTD entry).  I get an entry in my log file that looks similar
 * to this:
 *
 * 00/00/00 00:00:00  |   +- Begin Function: SomeClass::SomeFunction()
 * 00/00/00 00:00:00  |   |  [!] ERROR: exception: Access violation
 * 00/00/00 00:00:00  |   +- End
 *
 * I find this very useful in tracking down bugs.
 *
 * \param   a_iCode - Exception code.
 * \param   a_pExcPtr - Pointer to exception information.
 */
	void win32_Exception( unsigned int a_uiCode, _EXCEPTION_POINTERS* a_pExcPtr )
	{
		String sMsg;

		switch( a_uiCode )
		{
		case EXCEPTION_ACCESS_VIOLATION:         sMsg = "Access violation\n";         break;
		case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:    sMsg = "Array bounds exceeded\n";    break;
		case EXCEPTION_BREAKPOINT:               sMsg = "Breakpoint was encountered"; break;
		case EXCEPTION_DATATYPE_MISALIGNMENT:    sMsg = "Datatype misalignment\n";    break;
		case EXCEPTION_FLT_DENORMAL_OPERAND:     sMsg = "Float: Denormal operand\n";  break;
		case EXCEPTION_FLT_DIVIDE_BY_ZERO:       sMsg = "Float: Divide by zero\n";    break;
		case EXCEPTION_FLT_INEXACT_RESULT:       sMsg = "Float: Inexact result\n";    break;
		case EXCEPTION_FLT_INVALID_OPERATION:    sMsg = "Float: Invalid operation\n"; break;
		case EXCEPTION_FLT_OVERFLOW:             sMsg = "Float: Overflow\n";          break;
		case EXCEPTION_FLT_STACK_CHECK:          sMsg = "Float: Stack check\n";       break;
		case EXCEPTION_FLT_UNDERFLOW:            sMsg = "Float: Underflow\n";         break;
		case EXCEPTION_ILLEGAL_INSTRUCTION:      sMsg = "Illegal instruction\n";      break;
		case EXCEPTION_IN_PAGE_ERROR:            sMsg = "Page error\n";               break;
		case EXCEPTION_INT_DIVIDE_BY_ZERO:       sMsg = "Integer: Divide by zero\n";  break;
		case EXCEPTION_INT_OVERFLOW:             sMsg = "Integer: Overflow\n";        break;
		case EXCEPTION_INVALID_DISPOSITION:      sMsg = "Invalid disposition\n";      break;
		case EXCEPTION_NONCONTINUABLE_EXCEPTION: sMsg = "Noncontinuable exception\n"; break;
		case EXCEPTION_PRIV_INSTRUCTION:         sMsg = "Private Instruction\n";      break;
		case EXCEPTION_SINGLE_STEP:              sMsg = "Single step\n";              break;
		case EXCEPTION_STACK_OVERFLOW:           sMsg = "Stack overflow\n";           break;
		default: sMsg.Format( "Unknown exception code: %d\n" , a_uiCode );            break;
		}

		throw Error( "exception: " + sMsg );
	}

