Thursday, January 28, 2010

Exceptions: Win32 Structured Exceptions, C++ Exceptions, and Compiler Options.

In a Windows program that is written in the C++ language there are two types of exceptions that can be handled. The first is the Win32 structured exception that is built into the OS. The second are the C++ exceptions that are generally classes derived from std::exception.

To handle a Win32 structured exception you would have code like so:

__try {
// here is my code.
} __except(EXCEPTION_EXECUTE_HANDLER) {
// handle the exception here
}

To handle a C++ exception you would have code like this:

try {
// here is my code.
}
catch(std::exception &e) {
// handle exception here, should handle specific
// exceptions that you expect in production code
}
catch(...) {
// handle any other type of exception
// i.e. not derived from std::exception
}

The question is: What happens when a win32 SE is thrown and you are using C++ exceptions?

The answer: It depends on your compiler options!

Project Properties->Configuration Properties->C/C++->Code Generation->:Enable C++ Exceptions:

The choices are:
No
Yes (/EHsc)
Yes with with SEH Exceptions (/EHa)

If you use the setting No, you will get compiler warning C4530 for using C++ exceptions when they are not enabled. If you are treating warnings as errors like all professional programmers do, then you fix this compiler setting before going on. Runtime behavior is similar to Yes (/EHa).

If you use the setting Yes (/EHsc) C++ exceptions will be caught in catch handlers as you would expect. Win32 Structured Exceptions WILL NOT BE CAUGHT even by a catch(...) block!

If you use the setting Yes(/EHa) C++ exceptions will be caught in catch handlers as you would expect. Win32 Structured Exceptions WILL BE CAUGHT in catch(...) handlers only.

The moral of this story is: use the Yes(/EHa) setting at all times!

With the use of the Yes(/EHa) setting, you can use the function _set_se_translator to register a function that would be responsible for translating all Win32 structured exceptions into C++ exceptions. This helps to unify the error handling framework. Now you can use strongly typed C++ exceptions throughout your program. You should never have to use a catch(...) block again!

Example:

void my_translate(unsigned int code, _EXCEPTION_POINTERS *ep)
{
std::runtime_error re("translated win32 SE");
throw re;
}

// ... somewhere in WinMain... 
_set_se_translator(my_translate);

In Windows each thread has its own translator function which means that you must install your translator on each thread that you create.

No comments:

Post a Comment