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 );
}
|