130 likes | 267 Views
Win32 Programming. Lesson 23: SEH That’s right… you’ll never generate an exception, will you?. Where are we?. Looked at DLLs and their many facets But we’re not very good at handling errors yet… how does Windows do it?. Imagine. Your code will never generate an error
E N D
Win32 Programming Lesson 23: SEH That’s right… you’ll never generate an exception, will you?
Where are we? • Looked at DLLs and their many facets • But we’re not very good at handling errors yet… how does Windows do it?
Imagine • Your code will never generate an error • (Try really hard )
SEH • “Structured Exception Handling” • Basically, lets you assume the code is “good” and deal with the errors later • Very similar to the Java/C++ exception handling mechanism but different – don’t confuse the two • Mostly handled by the Compiler not the OS – special code is written to the application
So… • Introducing the Termination Handler • Guarantees that a particular block of code will be executed regardless of what happens above it • __try { // Guarded Body …} __finally { // Termination Handler …}
Example • DWORD Funcenstein1() { DWORD dwTemp; // 1. Do any processing here. __try { // 2. Request permission to access // protected data, and then use it. WaitForSingleObject(g_hSem, INFINITE); g_dwProtectedData = 5; dwTemp = g_dwProtectedData; } __finally { // 3. Allow others to use protected data. ReleaseSemaphore(g_hSem, 1, NULL); } // 4. Continue processing. return(dwTemp);}
But… • DWORD Funcenstein1() { DWORD dwTemp; // 1. Do any processing here. __try { // 2. Request permission to access // protected data, and then use it. WaitForSingleObject(g_hSem, INFINITE); g_dwProtectedData = 5; dwTemp = g_dwProtectedData;// Return the new value. return(dwTemp); } __finally { // 3. Allow others to use protected data. ReleaseSemaphore(g_hSem, 1, NULL); } // 4. Continue processing.dwTemp = 9; return(dwTemp);}
The Problem • Jumping from the __try to the __finally can be expensive in terms of CPU time • Called a local unwind
A Better Example • DWORD Funcfurter1() { DWORD dwTemp; // 1. Do any processing here. __try { // 2. Request permission to access // protected data, and then use it. WaitForSingleObject(g_hSem, INFINITE); dwTemp = Funcinator(g_dwProtectedData); } __finally { // 3. Allow others to use protected data. ReleaseSemaphore(g_hSem, 1, NULL); } // 4. Continue processing. return(dwTemp); } • What if Funcinator throws an access violation?
Quiz: What’s the output? • DWORD FuncaDoodleDoo() { DWORD dwTemp = 0; while (dwTemp < 10) { _ _try { if (dwTemp == 2) continue; if (dwTemp == 3) break; } _ _finally { dwTemp++; } dwTemp++; } dwTemp += 10; return(dwTemp); }
And Another… • DWORD Funcenstein4() { DWORD dwTemp; // 1. Do any processing here. _ _try { // 2. Request permission to access // protected data, and then use it. WaitForSingleObject(g_hSem, INFINITE); g_dwProtectedData = 5; dwTemp = g_dwProtectedData; // Return the new value. return(dwTemp); } _ _finally { // 3. Allow others to use protected data. ReleaseSemaphore(g_hSem, 1, NULL); return(103); } dwTemp = 9; return(dwTemp); }
Better Approach: __leave • Think of __leave as a normal exit that runs normally into __finally • This dramatically saves time and simplifies coding • However, it does complicate your code a little bit
But we’re still not done • Can see in the __finally block why we got there… • BOOL AbnormalTermination();