This article discusses briefly the Windows technology known as Structured Exception Handling, including its advantages and disadvantages, its capabilities, and various technical aspects of its use.
Much of the technical information is based on Jeffrey Richter’s last two chapters of Programming Applications for Microsoft Windows. I would like to thank him for writing and publishing a great book on Windows kernel programming.
Familiarity with C++ exception handling will help you understand this article, though it is not strictly necessary.
About This Article
This article explains the fundamentals of using structured exception handling, a Windows-specific technology that offers more power and flexibility and better performance than the C++ exception handling system. The reasons for this framework’s advantages are clear. For one, SEH supports exception filtering. It is possible, using SEH, to resolve a problem inside an exception filter function, or alternatively force the system to ignore this particular instance of an exception and skip it. In addition, SEH in Visual C++ offers an extremely valuable asset – termination handling. With termination handling, you can forget annoying cleanup code and painstaking, repeated return statements. Finally, the technology is available in C code – quite a blessing, really, considering that many applicationss use that language for fast processing. Moreover, C++ exception handling under Visual C++ carries speed and size overhead due to the immense amount of functions that can get called in the process and the data structures required by compilers to pull it off, while SEH, despite some additional functions that the compiler must generate and the OS kernel must call, is fast and reliable because the kernel is responsible for all the cleanup chores and because SEH refrains from making things more complex than they need to be. There is no doubt that in Windows, SEH is faster than C++ EH. Finally, SEH carries with it cross-language compatibility; I can write a DLL that raises a software exception in 2000, and my coworker’s great-grandchildren in 2100, using the magical language called X-Plus, can write a program that uses my DLL and catching the exception it raises. Try that with C++ EH, and you’ll find that it works only in C++ - and even then with possible headaches because the DLL attaches at runtime.
Quite dismayingly, using C++ exception handling is preferred over SEH in C++ unless SEH is used in a system-level routine or the programmer knows exactly what he is doing. The reason for this is that SEH fails to call object destructors after a block of code is abandoned due to a raised exception. It is possible to integrate SEH into C++, however. You are encouraged to experiment with various ways that SEH can be used in C++. From the concepts presented here, it should be relatively easy to deduce the side-effects of using SEH on a C++ compiler, and most compilers warn their users about inappropriate utilization of SEH in C++.
It’s time to make your next application as robust as it can get.
Fundamentals of SEH
Most current compilers provide an interface to SEH using three keywords and one API call, although there is a lot more to it than that. There are two types of exceptions: hardware exceptions, raised by the OS in response to processor or virtual machine events (e.g. divide by zero or invalid memory access), and software exceptions, raised by you or the Windows API or a component you are using. SEH is used to implement C++ exception handling in Microsoft Visual C++. The gory details of SEH’s own implementation are not required knowledge. This information is, however, available (see Microsoft Systems Journal article "A Crash Course on the Depths of Win32 Structured Exception Handling").
The three keywords used to interface with SEH are __try (preceded by two underscores), __except, and __finally. __try begins a code block and is paired with either __except or __finally. In both cases, it forms two blocks: code after the __try keyword, enclosed in braces, and code after the second keyword, also usually enclosed in braces. When it is paired with __except, it is called a try-except block. When it is paired with __finally, it produces a try-finally block. The API function RaiseException can be used to generate a software exception, akin to the C++ throw keyword. Please see the documentation for RaiseException in the Windows Platform SDK for more details
An important rule to remember in all cases when dealing with SEH is that you cannot jump into a try block. If such behavior were allowed, it would disturb the very principle upon which SEH (or C++ EH, for that matter) is based: structure. A similar rule is that jumps out of try blocks, although permitted, are best avoided because the compiler must go to pains to make it work. However, jumps within a try block are acceptable because no special code must be generated in that situation.