- Table of Contents
- Copyright
- About the Authors
- About the Contributors
- Acknowledgments
- Tell Us What You Think!
- Introduction
- How to Use This Book
- What You Need to Use This Book
- What's New in Visual C++ 6.0
- Contacting the Main Author
- Part I: Introduction
- Chapter 1. The Visual C++ 6.0 Environment
- Part II: MFC Programming
- Chapter 2. MFC Class Library Overview
- Chapter 3. MFC Message Handling Mechanism
- Chapter 4. The Document View Architecture
- Chapter 5. Creating and Using Dialog Boxes
- Chapter 6. Working with Device Contexts and GDI Objects
- Chapter 7. Creating and Using Property Sheets
- Chapter 8. Working with the File System
- Chapter 9. Using Serialization with File and Archive Objects
- Part III: Internet Programming with MFC
- Chapter 10. MFC and the Internet Server API (ISAPI)
- Chapter 11. The WinInet API
- Chapter 12. MFC HTML Support
- Part IV: Advanced Programming Topics
- Chapter 13. Using the Standard C++ Library
- Chapter 14. Error Detection and Exception Handling Techniques
- Structured Exception Handling
- C++ Exception Handling
- MFC Error and Exception Handling
- Summary
- Chapter 15. Debugging and Profiling Strategies
- Chapter 16. Multithreading
- Chapter 17. Using Scripting and Other Tools to Automate the Visual C++ IDE
- Part V: Database Programming
- Chapter 18. Creating Custom AppWizards
- Chapter 19. Database Overview
- Chapter 20. ODBC Programming
- Chapter 21. MFC Database Classes
- Chapter 22. Using OLE DB
- Chapter 23. Programming with ADO
- Part VI: MFC Support for COM and ActiveX
- Chapter 24. Overview of COM and Active Technologies
- Chapter 25. Active Documents
- Chapter 26. Active Containers
- Chapter 27. Active Servers
- Chapter 28. ActiveX Controls
- Part VII: Using the Active Template Library
- Chapter 29. ATL Architecture
- Chapter 30. Creating COM Objects Using ATL
- Chapter 31. Creating ActiveX Controls Using ATL
- Chapter 32. Using ATL to Create MTS and COM+ Components
- Part VIII: Finishing Touches
- Chapter 33. Adding Windows Help
- Part IX: Appendix
Structured Exception Handling
Structured exception handling is a way to handle exceptions within a program. It is a mechanism for handling both hardware and software exceptions. An exception is an event (most likely, an error) that occurs while the program is running. To prevent (or at least try to prevent) the program from crashing, the event may be captured, processed, reported, and hopefully handled properly so that the program can continue in a workable state. If exceptions are handled successfully, it allows for consistent reliable applications.
Note that although you can use SEH with C++, C++ exception handling should be used for C++, and MFC exception handling should be used for MFC programs. The SEH covered in this chapter is designed mainly for C programs written for Windows NT or Windows 95.
There are two types of exceptions: hardware exceptions and software exceptions. Hardware exceptions are triggered by the CPU. These exceptions usually are caused by illegal operations such as dividing by zero, floating-point overflow, disk read errors, null pointer accesses, array subscript range errors, and out-of-bounds memory addressing. Software exceptions always result from the operating system or the programs themselves, such as array subscript range errors, null pointer accesses, or invalid parameter specified.
Structured exception handling manages both hardware exceptions and software exceptions in the same manner. This makes it easier to handle exceptions, because either exception can be handled in the same manner. The advantage of this capability is that code used for recovery can remain the same without having to satisfy two different types of exceptions.
The Microsoft C/C++ Optimizing Compiler supports three major keywords to help use SEH:
| __try | Identifies a guarded body of code |
| __except | Identifies an exception handler |
| __finally | Identifies a termination handler |
The Structured Exception Method
The old way of handling exceptions was to pass error codes. A function would detect an error and pass that error to its calling function. This error then would be passed around until it reached a function that could properly handle it. What made this method weak was that the whole function would fail if there was a break in the series of function calls; therefore, the error code was unable to surface, and the error could never be handled properly.
Structured exception handling is different and more reliable in that once an exception handler is installed, the exception can be handled regardless of how many other functions are called.
The structure for the exception handlers follows:
__try {
guarded-code-block-1
}
__except ( filter ){
guarded-code-block-2
}
The statements that would exist in guarded-code-block-1 would be executed unconditionally. The exception handler defined by the filter and guarded-code-block-2 becomes the current exception handler.
If an exception occurs while guarded-code-block-1 is being executed, control is given to the current exception handler.
__try {
int number1 = 0;
int number2 = 0;
number1 = 100 / number2; //This is the exception to be handled.
}
__except( GetExceptionCode() == STATUS_INTEGER_DIVIDE_BY_ZERO )
{
printf( "Error: Divide By Zero!");
}
One limitation on using exception handlers is that you cannot use a goto statement to jump into a __try code block. The block must always be entered through the normal flow of control. You may jump out of a __try statement block, however.
A Look at Software Exceptions
You raise software exceptions by calling the RaiseException function. Keep in mind that you may treat any condition as an exception by reporting the condition to the RaiseException function. You can flag any type of runtime error this way.
To perform exception reporting with software errors, you must do the following:
- Define the exception code for the event.
- Call the RaiseException function when the error is detected.
- Use exception-handling filters for the defined exception codes.
You can find the format for exception codes in the WINERROR.H header file. When defining your own exception code, make sure to set the third-most-significant bit to 1.
Setting the fourth-most-significant bits is a little more involved. Bits 31 to 30 define the basic status of the code. Bit 00 = success, 11 = error, 01 = informational, and 10 = warning. Bit 29 is the client bit and should be set to 1 for user-defined codes. Bit 28 is a reserved bit and should be set to 0.
Defined exception codes that do not conflict with the exceptions codes of Windows NT may look like the following:
#define STATUS_BAD_ERROR_01 0xE0000001 #define STATUS_BAD_ERROR_01 0xE0000001 #define STATUS_BAD_ERROR_01 0xE0000001
Testing your defined exception is quite simple and may look like the following:
__try {
//Guarded code is goes here
}
__except (GetExceptionCode() == STATUS_BAD_ERROR_01) ||
GetExceptionCode() == STATUS_BAD_ERROR_02) ||
GetExceptionCode() == STATUS_BAD_ERROR_03))
A Look at Hardware Exceptions
Hardware exceptions make up the majority of the standard exceptions. The hardware exceptions that Windows NT recognizes follow:
- STANDARD_ACCESS_VIOLATION—Reading or writing to an invalid/inaccessible memory location.
- STATUS_BREAKPOINT—A hardware-defined breakpoint is being encountered. Used by debuggers only.
- STATUS_DATATYPE_MISALIGNMENT—Reading or writing to data at an improperly aligned address.
- STATUS_FLOATING_DIVIDE_BY_ZERO—Dividing floating-point type by 0.
- STATUS_FLOATING_OVERFLOW—The range of the maximum exponent of a floating point is being exceeded.
- STATUS_FLOATING_RESERVED_OPERAND—Using a reserved floating-point format.
- STATUS_FLOATING_UNDERFLOW—The range of the lowest negative exponent of the floating point is being exceeded.
- STATUS_ILLEGAL_INSTRUCTION—An instruction code that is undefined is trying to be executed.
- STATUS_INTEGER_DIVIDE_BY_ZERO—Dividing integer type by 0.
- STATUS_INTEGER_OVERFLOW—The range of the integer is being exceeded.
- STATUS_PRIVILEGED_INSTRUCTION—An instruction not allowed in the current machine mode is trying to be executed.
- STATUS_SINGLE_STEP—One instruction at a time is being executed (single-step mode). Used by debuggers only.
Most of the exceptions in the preceding list are intended to be handled by debuggers, low-level code, or the operating system itself. The only types of code you should be handling are the integer and floating-point errors. The most likely line of action for the other exceptions is to ignore the exceptions and evaluate them to zero. By not doing so, lower-level mechanisms may not respond to the exception error as they should.
Structured Exception Handling Functions
The following functions are used in SEH:
- AbnormalTermination
- GetExceptionCode
- GetExceptionInformation
- RaiseException
- SetUnhandledExceptionFilter
- UnhandledExceptionFilter
You'll examine these functions in the following sections.
AbnormalTermination
The AbnormalTermination function returns zero if the __try block terminated normally and nonzero if the __try block terminated abnormally. This function can be called only from within a __finally block of a termination handler.
GetExceptionCode
The GetExceptionCode function returns a code that identifies the type of exception that occurred. This function may be called only from an exception-handler block of an exception handler or from within the filter expression.
Here is a list of GetExceptionCode return values:
- EXCEPTION_ACCESS_VIOLATION—The thread tried to read from or write to a virtual address that it does not have access to.
- EXCEPTION_ARRAY_BOUNDS_EXCEEDED—The thread tried to access an out-of-bounds array element.
- EXCEPTION_BREAKPOINT—A breakpoint occurred.
- EXCEPTION_DATATYPE_MISALIGNMENT—The tread tried to read or write data on hardware that is misaligned.
- EXCEPTION_FLT_DENORMAL_OPERAND—An operand in a floating-point value is too small to be represented as a standard floating-point value.
- EXCEPTION_FLT_DIVIDE_BY_ZERO—The thread attempted to divide a floating-point value by a divisor of zero.
- EXCEPTION_FLT_INEXACT_RESULT—The resulting floating-point operation cannot be represented exactly as a decimal fraction.
- EXCEPTION_FLT_INVALID_OPERATION—Returned for every floating-point exception not met by any floating-point exceptions listed here.
- EXCEPTION_FLT_OVERFLOW—The exponent of a floating-point operation is larger than allowed by the corresponding type.
- EXCEPTION_FLT_STACK_CHECK—The stack underflowed or overflowed by a floating-point operation.
- EXCEPTION_FLT_UNDERFLOW—The exponent of a floating-point operation is smaller than allowed by the corresponding type.
- EXCEPTION_INT_DIVIDE_BY_ZERO—The thread attempted to divide an integer value by a divisor of zero.
- EXCEPTION_INT_OVERFLOW—The resulting integer value was too large to store, resulting in the carry out of the most significant bit.
- EXCEPTION_NONCONTINUABLE_EXCEPTION—The thread tried to continue executing after a noncontinuable exception occurred.
- EXCEPTION_PRIV_INSTRUCTION—The thread tried to execute an instruction not permitted in the current machine mode.
- EXCEPTION_SINGLE_STEP—A trace trap signaled that one instruction was executed.
These return values can be passed as a parameter to a filter function.
GetExceptionInformation
The GetExceptionInformation function returns a machine-independent description of an exception, as well as information about the machine state that existed for the thread when the exception occurred.
The return value is a pointer to the structure EXCEPTION_POINTERS. This structure contains pointers to two other structures: EXCEPTION_RECORD and CONTEXT. EXCEPTION_RECORD contains a description of the exception. The CONTEXT structure contains the machine-state information.
RaiseException
The RaiseException function handles private application-defined exceptions that are software-generated.
When an exception is raised, the exception dispatcher goes through the following steps:
- If the process is being debugged, the process's debugger is notified.
- If the process is not being debugged or the debugger cannot handle the exception, the system searches the stack frames of thread where the exception occurred for a frame-based exception handler. The current stack frame is searched first, and then the previous stack frames are searched.
- If no frame-based handler is found, or the frame-based handler cannot handle the exception, a second attempt is made to notify the process's debugger.
- If the debugger cannot handle the exception, or the process is not being debugged, the system provides default handling based on the exception type. The default action of most exceptions is to call the ExitProcess function.
The ExitProcess Function
The ExitProcess function terminates a process as well as all its threads. It is the preferred way of ending a processing, because it provides a clean ending of a process.
SetUnhandledExceptionFilter
The SetUnhandledExceptionFilter function allows an application to replace the top-level exception handler that Win32 places at the beginning of each process and thread.
This filter function takes a single parameter type of LPEXCEPTION_POINTERS and returns a value of type LONG. The following list describes the SetUnhandledExceptionFilter return values:
- EXCEPTION CONTINUE EXECUTION—Indicates to continue execution from the point of exception
- EXCEPTION CONTINUE SEARCH—Indicates to proceed with normal execution
- EXCEPTION_EXECUTE HANDLER—Usually indicates the termination of a process
UnhandledExceptionFilter
If the process is being debugged, the UnhandledExceptionFilter function sends unhandled exceptions to the debugger. If the process is not being debugged, the function displays an Application Error message box and executes the exception handler.
The UnhandledExceptionFilter function returns two values:
- EXCEPTION_CONTINUE_SEARCH—The exception is passed to the application's debugger.
- EXCEPTION_EXECUTE_HANDLER—Control is returned to the exception handler.
Remember that SEH is used mainly for C programs, not C++. Although you can use SEH for C++, the next section shows a better method.
C++ Exception Handling | Next Section

Account Sign In
View your cart