170 likes | 295 Vues
In this lesson, we delve deeper into Structured Exception Handling (SEH) in Win32 programming, focusing on the use of `__except` and its interaction with `__try` blocks. We explore the structure and differences between exception handling and finalization, highlighting examples that showcase exception management in action. Learn how to gracefully handle exceptions without terminating your program, manage error states, and understand the implications of global unwinds. We also touch on the complexities of exception code handling and performance considerations when exceptions arise.
E N D
Win32 Programming Lesson 24: More SEH That’s right… you’ll never generate an exception, will you?
Where are we? • Looked at __finally blocks… • But you can also deal with the exception using __except
Basic structure • __try { //code} __except { //exception handler} • Note: you can’t have __except and __finally in the same __try block
Example • DWORD Funcmeister1() { DWORD dwTemp; // 1. Do any processing here. _ try { // 2. Perform some operation. dwTemp = 0; } except (EXCEPTION_EXECUTE_HANDLER) { // Handle an exception; this never executes. } // 3. Continue processing. return(dwTemp); }
Better Example • DWORD Funcmeister2() { DWORD dwTemp = 0; // 1. Do any processing here. __try { // 2. Perform some operation(s). dwTemp = 5 / dwTemp; // Generates an exception dwTemp += 10; // Never executes } __except (EXCEPTION_EXECUTE_HANDLER) { // 4. Handle an exception. MessageBeep(0); } // 5. Continue processing. return(dwTemp); }
Example • See what was new? • __except (*) where * == • EXCEPTION_EXECUTE_HANDLER • EXCEPTION_CONTINUE_SEARCH • EXCEPTION_CONTINUE_EXECUTION
EXCEPTION_EXECUTE_HANDLER • Execute the __except block and continue after it • Very useful for getting yourself out of trouble… • char* RobustStrCpy( char* strDestination, const char* strSource) { __try { strcpy(strDestination, strSource); } __except (EXCEPTION_EXECUTE_HANDLER) { // Nothing to do here } return(strDestination); } • Never causes the program to exit • However, does cause a global unwind…
Global Unwind? • Essentially, the computer has to unwind _try blocks (because the __finally clauses have to be executed) until it gets to the handling __except block • That’s expensive in terms of CPU cycles
Odd Errors • Of course, EXCEPTION_CONTINUE_EXECUTION can cause strange errors • Imagine: • *buf = ‘R’ • Assembles as: mov eax, [buf]; mov [eax], ‘R’ • When we continue after fixing the error, what happens depends on the target CPU and the compiler optimizations • BE WARNED!
EXECUTE_CONTINUE_SEARCH • Go up to the previous __except block and use that exception handler… • But doesn’t call __finally blocks • This can make code hard to follow (remember our example from last week?)
Deciding what to do • As we saw in the previous example, we can decide what to do in the __except () block with a function • Sometimes we want to know what type of exception occurred • Done with DWORD GetExceptionCode • Values defined in winbase.h
So… • _ _try { x = 0; y = 4 / x; } _ _except ((GetExceptionCode() == EXCEPTION_INT_DIVIDE_BY_ZERO) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { // Handle divide by zero. }
Under The Hood • When an exception occurs, the OS pushes three structures to the calling thread’s stack • EXCEPTION_RECORD • CONTEXT • EXCEPTION_POINTERS • Can access via • PEXECEPTION_POINTERS GetExceptionInformation()
Finally… • (Or do I mean __finally?) • Remind me what happens inside the kernel when we start a process?
ThreadStart/ProcStart • The primary thread (and subsequent threads) are wrapped in a __try __except block • It’s this block which ultimately cancels the process/thread • I’m sure you’ve all seen the box • Now you know where it comes from!
Assignment • No assignment today… • Lucky ewe…