SAMPLE: EXCEPTEX Traps MFC and Win32 Structured ExceptionsID: Q167802
|
EXCEPTEX is a sample that demonstrates techniques for trapping of both
Win32 Structured Exceptions and C++ Exceptions. For C++ exceptions, various
helper functions are provided that demonstrate how to crack open the more
commonly used exception classes. For Win32 Structured Exceptions, a helper
function is provided that identifies the type of Win32 exception thrown.
The following files is available for download from the Microsoft
Software Library:
~ Exceptex.exeFor more information about downloading files from the Microsoft Software Library, please see the following article in the Microsoft Knowledge Base:
Q119591 How to Obtain Microsoft Support Files from Online Services
// C++ Exception Handler
try
{
// Do something that may raise an exception
}
catch( <class name> <instance of class> )
{
// handle exception
}
// Win32 Structured Exception Handler
__try
{
// Do something that may raise an exception
}
__except( expression )
{
// handle exception
}
The fundamental difference being that C++ exception handling expects to
catch an instance of a type, whereas Win32 Structured Exception Handling
catches only three unsigned ints.
// Class for containing information on a Win32 Structured Exception
class SEH_Exception {
private:
SEH_Exception() {}
unsigned int m_uSECode;
public:
SEH_Exception(unsigned int uSECode) : m_uSECode(uSECode) {}
~SEH_Exception() {}
unsigned int getSeHNumber() { return m_uSECode; }
};
// Handler function that passes on Win32 Exception information in the
// C++ class SEH_Exception
void MappingSEHtoCPPExceptions( unsigned int uExceptionCode,
_EXCEPTION_POINTERS* )
{
throw SEH_Exception( uExceptionCode );
}
// Initialize Exception Handling
void LogEnable( ... )
{
// Set Win32 Exceptions to be handled as C++ typed exceptions
_set_se_translator(MappingSEHtoCPPExceptions);
...
}
In this case, LogEnable would be called once, early in the program's
execution, and any Win32 exceptions raised could be caught with C++ syntax.
The EXCEPTEX sample demonstrates this using the code given above.
// Crack open and log details of different types of exceptions
extern void LogException( CException *e,
LPCSTR lpszTimeStamp,
LPCSTR lpszFile,
int nLine );
LogException also tracks the file name and line number where the exception
macro was last used in the call stack (if used with a helper LOG macro).
#if _MSC_VER < 1100 // For version VC++ 4.2 or earlier
#define LOGQ( f ) if( bRetVal == TRUE ) \
{ \
try \
{ \
f; \
} \
catch( CException *e ) \
{ \
bRetVal = FALSE; \
e->Delete(); \
} \
catch( SEH_Exception ) \
{ \
bRetVal = FALSE; \
} \
catch(...) \
{ \
bRetVal = FALSE; \
} \
}
#else
#define LOGQ( f ) if( bRetVal == TRUE ) \
{ \
try \
{ \
f; \
} \
catch( CException *e ) \
{ \
bRetVal = FALSE; \
e->Delete(); \
} \
catch( _com_error ) \
{ \
bRetVal = FALSE; \
} \
catch( SEH_Exception ) \
{ \
bRetVal = FALSE; \
} \
catch(...) \
{ \
bRetVal = FALSE; \
} \
}
#endif
The #ifdef _MSC_VER restricts the definition of the macro to be specific to
either Visual C++ 4.X or 5.0. The 5.0 version includes a catch for the
newly introduced _com_error exception (generated by code created from
#import).
int i = 0;
int j;
BOOL bRetVal = TRUE;
// This code is not safe
j = 1 / i; // Raises Win32 Divide By Zero exception
// This code is safe
LOGQ( j = 1 / i; )
There are two other versions of the LOG macros provided by EXCEPTEX. The
second LOG macro uses the overloaded LogException() helpers described
above.
#define LOGE( f ) try \
{ \
f; \
} \
catch( CException *e ) \
{ \
LogException( e, \
__TIMESTAMP__, \
__FILE__, \
__LINE__ );\
} \
...
This macro does not make use of the flag bRetVal. It will always execute
the code encapsulated by the macro, catch any exceptions raised and log
their contents.
#define LOGR( f ) if( bRetVal == TRUE ) \
{ \
try \
{ \
f; \
} \
catch( CException *e ) \
{ \
LogException( e, \
__TIMESTAMP__, \
__FILE__, \
__LINE__ );\
bRetVal = FALSE; \
} \
...
}
LogDisplay() Dumps contents of all logged exceptions out via TRACE macros.
LogDisplay( ... ) Dumps contents of all logged exceptions out to an instance of CListBox.
LogSaveToFile( ... ) Dumps contents of all logged exceptions out to a file.
// One time initialization of data
LogEnable(false); // false to verbose mode
Add the LOG macro in code you want to get exception data from.
...
LOGE(myFunction())
...
Note that the file and line number reported will be the last LOG macro on
the stack. If myFunction() calls myFun1() and myFun2(), you will have to
wrap each function call with a LOG macro for the output to display which
call the exception occurred in.
LOGQ( int i = 0; )
LOGQ( int j = 1 / i; ) // Will this raise a divide by zero?
This code generates a compiler error as i is only defined in the scope
of the first LOGQ macro. Remember that LOGQ expands to:
>
...
try
{
int i = 0;
}
...
...
try
{
int j = 1 / i; // error C2065: 'i' : undeclared
}
...
comutil.h(905) : warning C4310: cast truncates constant valueThese error messages can be ignored and should not affect your code.
comutil.h(928) : warning C4310: cast truncates constant value
comutil.h(1030) : warning C4310: cast truncates constant value
comutil.h(1281) : warning C4310: cast truncates constant value
comutil.h(1307) : warning C4310: cast truncates constant value
comutil.h(1476) : warning C4310: cast truncates constant value
comdef.h(242) : warning C4244: 'return' : conversion from 'int' to 'unsigned short', possible loss of data
Exception Handling: Frequently Asked QuestionsThe following article demonstrates techniques that could be used to expand the EXCEPTEX sample to handle DAO SDK exceptions.
mk:@ivt:vccore/F26/D2A/S31BE4.HTM
Exception Handling Differences
mk:@ivt:vccore/F26/D2B/S4CC99.HTM
Q152695 How to Catch and Decipher DAO SDK-Based ExceptionsA definitive source on Win32 Exception Handling can be found in:
Keywords : kbsample kbnokeyword kbDAO kbDatabase kbMFC kbODBC kbVC
Version : WINDOWS NT: 4.0, 4.1, 4.2, 5.0
Platform : NT WINDOWS
Issue type :
Last Reviewed: July 14, 1999