2002-05-28 21:13:45 +08:00
|
|
|
int
|
|
|
|
__except_handler3(
|
|
|
|
struct _EXCEPTION_RECORD* pExceptionRecord,
|
|
|
|
struct EXCEPTION_REGISTRATION* pRegistrationFrame,
|
|
|
|
struct _CONTEXT* pContextRecord,
|
|
|
|
void* pDispatcherContext
|
|
|
|
)
|
|
|
|
{
|
|
|
|
LONG filterFuncRet;
|
|
|
|
LONG trylevel;
|
|
|
|
EXCEPTION_POINTERS exceptPtrs;
|
|
|
|
PSCOPETABLE pScopeTable;
|
|
|
|
|
|
|
|
|
|
|
|
CLD // Clear the direction flag (make no assumptions!)
|
|
|
|
|
|
|
|
// if neither the EXCEPTION_UNWINDING nor EXCEPTION_EXIT_UNWIND bit
|
|
|
|
// is set... This is true the first time through the handler (the
|
|
|
|
// non-unwinding case)
|
|
|
|
|
|
|
|
if ( ! (pExceptionRecord->ExceptionFlags
|
|
|
|
& (EXCEPTION_UNWINDING | EXCEPTION_EXIT_UNWIND)
|
|
|
|
) )
|
|
|
|
{
|
|
|
|
// Build the EXCEPTION_POINTERS structure on the stack
|
|
|
|
exceptPtrs.ExceptionRecord = pExceptionRecord;
|
|
|
|
exceptPtrs.ContextRecord = pContextRecord;
|
|
|
|
|
|
|
|
// Put the pointer to the EXCEPTION_POINTERS 4 bytes below the
|
|
|
|
// establisher frame. See ASM code for GetExceptionInformation
|
|
|
|
*(PDWORD)((PBYTE)pRegistrationFrame - 4) = &exceptPtrs;
|
|
|
|
|
|
|
|
// Get initial "trylevel" value
|
|
|
|
trylevel = pRegistrationFrame->trylevel
|
|
|
|
|
|
|
|
// Get a pointer to the scopetable array
|
|
|
|
scopeTable = pRegistrationFrame->scopetable;
|
|
|
|
|
|
|
|
search_for_handler:
|
|
|
|
if ( pRegistrationFrame->trylevel != TRYLEVEL_NONE )
|
|
|
|
{
|
|
|
|
if ( pRegistrationFrame->scopetable[trylevel].lpfnFilter )
|
|
|
|
{
|
|
|
|
|
|
|
|
PUSH EBP // Save this frame EBP
|
|
|
|
|
|
|
|
// !!!Very Important!!! Switch to original EBP. This is
|
|
|
|
// what allows all locals in the frame to have the same
|
|
|
|
// value as before the exception occurred.
|
|
|
|
|
|
|
|
EBP = &pRegistrationFrame->_ebp
|
|
|
|
|
|
|
|
// Call the filter function
|
|
|
|
filterFuncRet = scopetable[trylevel].lpfnFilter();
|
|
|
|
|
|
|
|
POP EBP // Restore handler frame EBP
|
|
|
|
|
|
|
|
if ( filterFuncRet != EXCEPTION_CONTINUE_SEARCH )
|
|
|
|
{
|
|
|
|
if ( filterFuncRet < 0 ) // EXCEPTION_CONTINUE_EXECUTION
|
|
|
|
return ExceptionContinueExecution;
|
|
|
|
|
|
|
|
// If we get here, EXCEPTION_EXECUTE_HANDLER was specified
|
|
|
|
scopetable == pRegistrationFrame->scopetable
|
|
|
|
|
|
|
|
// Does the actual OS cleanup of registration frames
|
|
|
|
// Causes this function to recurse
|
|
|
|
__global_unwind2( pRegistrationFrame );
|
|
|
|
|
|
|
|
|
|
|
|
// Once we get here, everything is all cleaned up, except
|
|
|
|
// for the last frame, where we'll continue execution
|
|
|
|
EBP = &pRegistrationFrame->_ebp
|
|
|
|
|
|
|
|
__local_unwind2( pRegistrationFrame, trylevel );
|
|
|
|
|
|
|
|
// NLG == "non-local-goto" (setjmp/longjmp stuff)
|
|
|
|
__NLG_Notify( 1 ); // EAX == scopetable->lpfnHandler
|
|
|
|
|
|
|
|
// Set the current trylevel to whatever SCOPETABLE entry
|
|
|
|
// was being used when a handler was found
|
|
|
|
pRegistrationFrame->trylevel = scopetable->previousTryLevel;
|
|
|
|
|
|
|
|
// Call the _except {} block. Never returns.
|
|
|
|
pRegistrationFrame->scopetable[trylevel].lpfnHandler();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
scopeTable = pRegistrationFrame->scopetable;
|
|
|
|
trylevel = scopeTable->previousTryLevel
|
|
|
|
|
|
|
|
goto search_for_handler;
|
|
|
|
}
|
|
|
|
else // trylevel == TRYLEVEL_NONE
|
|
|
|
{
|
|
|
|
retvalue == DISPOSITION_CONTINUE_SEARCH;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else // EXCEPTION_UNWINDING or EXCEPTION_EXIT_UNWIND flags are set
|
|
|
|
{
|
|
|
|
PUSH EBP // Save EBP
|
|
|
|
|
|
|
|
EBP = pRegistrationFrame->_ebp // Set EBP for __local_unwind2
|
|
|
|
|
|
|
|
__local_unwind2( pRegistrationFrame, TRYLEVEL_NONE )
|
|
|
|
|
|
|
|
POP EBP // Restore EBP
|
|
|
|
|
|
|
|
retvalue == DISPOSITION_CONTINUE_SEARCH;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|