📄 seh.gml
字号:
_try {
_try {
func_level3();
}
_except (EXCEPTION_CONTINUE_SEARCH) {
printf( "Exception never handled in func_level2\n" );
}
}
_finally {
if( AbnormalTermination() )
printf( "Unwind in func_level2\n" );
}
printf( "Normal return from func_level2\n" );
}
.tinyexam break
void func_level1( void )
{
_try {
func_level2();
}
_finally {
if( AbnormalTermination() )
printf( "Unwind in func_level1\n" );
}
printf( "Normal return from func_level1\n" );
}
.tinyexam break
void func_level0( void )
{
_try {
_try {
func_level1();
}
_except (EXCEPTION_EXECUTE_HANDLER) {
printf( "Exception handled in func_level0\n" );
}
}
_finally {
if( AbnormalTermination() )
printf( "Unwind in func_level0\n" );
}
printf( "Normal return from func_level0\n" );
}
.tinyexam break
void main( int argc, char **argv )
{
_try {
_try {
func_level0();
}
_except (EXCEPTION_EXECUTE_HANDLER) {
printf( "Exception handled in main\n" );
}
}
_finally {
if( AbnormalTermination() )
printf( "Unwind in main\n" );
}
printf( "Normal return from main\n" );
}
.tinyexam end
.np
In this example,
.autonote
.note
.id main
calls
.id func_level0
.note
.id func_level0
calls
.id func_level1
.note
.id func_level1
calls
.id func_level2
.note
.id func_level2
calls
.id func_level3
.note
.id func_level3
calls
.id func_level4
.endnote
.np
It is in
.id func_level4
where the exception occurs.
The run-time system traps the exception and performs a search
of the active
.us try
blocks looking for one that is paired up with an
.us except
block.
.np
.ix 'EXCEPTION_EXECUTE_HANDLER'
When it finds one, the filter is executed and, if the result is
.id EXCEPTION_EXECUTE_HANDLER,
then the
.us except
block is executed after performing a global unwind.
.np
.ix 'EXCEPTION_CONTINUE_EXECUTION'
If the result is
.id EXCEPTION_CONTINUE_EXECUTION,
the run-time system resumes execution at the instruction that
caused the exception.
.np
.ix 'EXCEPTION_CONTINUE_SEARCH'
If the result is
.id EXCEPTION_CONTINUE_SEARCH,
the run-time system continues its search for an
.us except
block with a filter that returns one of the other possible values.
If it does not find any exception handler that is prepared to handle
the exception, the application will be terminated with the appropriate
exception notification.
.np
Let us look at the result of executing the example program.
The following messages are printed.
.millust begin
Attempting illegal memory reference
Unwind in func_level4
Unwind in func_level3
Unwind in func_level2
Unwind in func_level1
Exception handled in func_level0
Normal return from func_level0
Normal return from main
.millust end
.np
The run-time system searched down the
.us try/except
chain until it got to
.id func_level0
which had an
.us except
filter that evaluated to
.id EXCEPTION_EXECUTE_HANDLER.
It then performed a global unwind in which the
.us try/finally
blocks of
.id func_level4,
.id func_level3,
.id func_level2,
and
.id func_level1
were executed.
After this, the exception handler in
.id func_level0
did its thing and execution resumed in
.id func_level0
which returned back to
.id main
which returned to the run-time system for normal program termination.
Note the use of the built-in
.kw AbnormalTermination
function in the
.us finally
blocks of each function.
.np
This sequence of events permits each function to do any cleaning up
that it deems necessary before it is wiped off the execution stack.
.*
.section Refining Exception Handling
.*
.np
The decision to handle an exception must be weighed carefully.
It is not necessarily a desirable thing for an exception handler to
handle all exceptions.
.ix 'EXCEPTION_EXECUTE_HANDLER'
In the previous example, the expression in the exception filter in
.id func_level0
always evaluates to
.id EXCEPTION_EXECUTE_HANDLER
which means it will snag every exception that comes its way.
There may be other exception handlers further on down the chain that
are better equipped to handle certain types of exceptions.
.ix 'GetExceptionCode'
There is a way to determine the exact type of exception using the
built-in
.id GetExceptionCode()
function.
It may be called only from within the exception handler filter
expression or within the exception handler block.
Here is a description of the possible return values from the
.id GetExceptionCode()
function.
.begnote $break $setptnt 15
.notehd1 Value
.notehd2 Meaning
.note EXCEPTION_ACCESS_VIOLATION
.ix 'EXCEPTION_ACCESS_VIOLATION'
The thread tried to read from or write to a virtual address for which
it does not have the appropriate access.
.note EXCEPTION_BREAKPOINT
.ix 'EXCEPTION_BREAKPOINT'
A breakpoint was encountered.
.note EXCEPTION_DATATYPE_MISALIGNMENT
The thread tried to read or write data that is misaligned on hardware
that does not provide alignment. For example, 16-bit values must be
aligned on 2-byte boundaries; 32-bit values on 4-byte boundaries, and
so on.
.note EXCEPTION_SINGLE_STEP
.ix 'EXCEPTION_SINGLE_STEP'
A trace trap or other single-instruction mechanism signaled that one
instruction has been executed.
.note EXCEPTION_ARRAY_BOUNDS_EXCEEDED
The thread tried to access an array element that is out of bounds and
the underlying hardware supports bounds checking.
.note EXCEPTION_FLT_DENORMAL_OPERAND
.ix 'EXCEPTION_FLT_DENORMAL_OPERAND'
One of the operands in a floating-point operation is denormal. A
denormal value is one that is too small to represent as a standard
floating-point value.
.note EXCEPTION_FLT_DIVIDE_BY_ZERO
.ix 'EXCEPTION_FLT_DIVIDE_BY_ZERO'
The thread tried to divide a floating-point value by a floating-point
divisor of zero.
.note EXCEPTION_FLT_INEXACT_RESULT
.ix 'EXCEPTION_FLT_INEXACT_RESULT'
The result of a floating-point operation cannot be represented exactly
as a decimal fraction.
.note EXCEPTION_FLT_INVALID_OPERATION
.ix 'EXCEPTION_FLT_INVALID_OPERATION'
This exception represents any floating-point exception not included in
this list.
.note EXCEPTION_FLT_OVERFLOW
.ix 'EXCEPTION_FLT_OVERFLOW'
The exponent of a floating-point operation is greater than the
magnitude allowed by the corresponding type.
.note EXCEPTION_FLT_STACK_CHECK
.ix 'EXCEPTION_FLT_STACK_CHECK'
The stack overflowed or underflowed as the result of a floating-point
operation.
.note EXCEPTION_FLT_UNDERFLOW
.ix 'EXCEPTION_FLT_UNDERFLOW'
The exponent of a floating-point operation is less than the magnitude
allowed by the corresponding type.
.note EXCEPTION_INT_DIVIDE_BY_ZERO
The thread tried to divide an integer value by an integer divisor of
zero.
.note EXCEPTION_INT_OVERFLOW
.ix 'EXCEPTION_INT_OVERFLOW'
The result of an integer operation caused a carry out of the most
significant bit of the result.
.note EXCEPTION_PRIV_INSTRUCTION
.ix 'EXCEPTION_PRIV_INSTRUCTION'
The thread tried to execute an instruction whose operation is not
allowed in the current machine mode.
.note EXCEPTION_NONCONTINUABLE_EXCEPTION
.ix 'EXCEPTION_NONCONTINUABLE_EXCEPTION'
The thread tried to continue execution after a non-continuable exception
occurred.
.endnote
.np
These constants are defined by including
.fi WINDOWS.H
in the source code.
.np
The following example is a refinement of the
.id func_level1()
function in our previous example.
.tinyexam begin
#include <windows.h>
void func_level0( void )
{
_try {
_try {
func_level1();
}
_except (
(GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION)
? EXCEPTION_EXECUTE_HANDLER
: EXCEPTION_CONTINUE_SEARCH
) {
printf( "Exception handled in func_level0\n" );
}
}
_finally {
if( AbnormalTermination() )
printf( "Unwind in func_level0\n" );
}
printf( "Normal return from func_level0\n" );
}
.tinyexam end
.np
.ix 'access violation'
In this version, only an "access violation" will be handled by the
exception handler in the
.id func_level0()
function.
All other types of exceptions will be passed on to
.id main
(which can also be modified to be somewhat more selective about the
types of exceptions it should handle).
.np
.ix 'GetExceptionInformation'
More information on the exception that has occurred can be obtained by
the use of the
.id GetExceptionInformation()
function.
The use of this function is also restricted.
It can be called only from within the filter expression of an
exception handler.
However, the return value of
.id GetExceptionInformation()
can be passed as a parameter to a filter function.
This is illustrated in the following example.
.tinyexam begin
int GetCode( LPEXCEPTION_POINTERS exceptptrs )
{
return (exceptptrs->ExceptionRecord->ExceptionCode );
}
void func_level0( void )
{
_try {
_try {
func_level1();
}
_except (
(GetCode( GetExceptionInformation() )
== EXCEPTION_ACCESS_VIOLATION)
? EXCEPTION_EXECUTE_HANDLER
: EXCEPTION_CONTINUE_SEARCH
) {
printf( "Exception handled in func_level0\n" );
}
}
_finally {
if( AbnormalTermination() )
printf( "Unwind in func_level0\n" );
}
printf( "Normal return from func_level0\n" );
}
.tinyexam end
.np
.ix 'GetExceptionInformation'
The return value of
.id GetExceptionInformation()
is a pointer to an
.ix 'EXCEPTION_POINTERS'
.id EXCEPTION_POINTERS
structure that contains pointers to two other structures: an
.ix 'EXCEPTION_RECORD'
.id EXCEPTION_RECORD
structure containing a description of the exception, and a
.ix 'CONTEXT'
.id CONTEXT
structure containing the machine-state information.
The filter function can make a copy of the structures if a more
permanent copy is desired.
Check your Win32 SDK documentation for more information on these
structures.
.*
.section Throwing Your Own Exceptions
.*
.np
You can use the same exception handling mechanisms to deal with
software exceptions raised by your application.
.ix 'RaiseException'
The
.id RaiseException()
function can be used to throw your own application-defined exceptions.
The first argument to this function is the exception code.
It would be wise to define your exception codes so that they do not
collide with system defined ones.
The following example shows how to throw an exception.
.exam begin
#define MY_EXCEPTION ( (DWORD) 123L )
RaiseException( MY_EXCEPTION,
EXCEPTION_NONCONTINUABLE,
0, NULL );
.exam end
.np
In this example, the
.id GetExceptionCode()
function, when used in an exception handler filter expression or in
the body of an exception handler, would return the value 123.
.np
.ix 'RaiseException'
See the Win32 SDK documentation for more information on the arguments
to the
.id RaiseException()
function.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -