170 likes | 274 Views
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 }
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…