例外ハンドラーの記述
次の例では、例外ハンドラーの使用方法を示します。
例 1
次のコード部分は、構造化例外処理を使用して、2 つの 32 ビット整数の除算演算で 0 除算エラーが発生するかどうかをチェックします。 この場合、関数は FALSE を返します。それ以外の場合は TRUE を返します。
BOOL SafeDiv(INT32 dividend, INT32 divisor, INT32 *pResult)
{
__try
{
*pResult = dividend / divisor;
}
__except(GetExceptionCode() == EXCEPTION_INT_DIVIDE_BY_ZERO ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
{
return FALSE;
}
return TRUE;
}
例 2
次の例の関数は、DebugBreak 関数を呼び出し、構造化例外処理を使用してブレークポイント例外をチェックします。 この場合、関数は FALSE を返します。それ以外の場合は TRUE を返します。
この例のフィルター式では、GetExceptionCode 関数を使用して、ハンドラーを実行する前に例外の種類をチェックします。 これにより、他のタイプの例外が発生した場合でも、システムは適切なハンドラーの検索を続行できます。
また、例外ハンドラーの __try ブロックで return ステートメントを使用することは、終了ハンドラーの __try ブロックでの return の使用とは異なり、__try ブロックが異常終了します。 これは、例外ハンドラーでの return ステートメントの有効な使用です。
BOOL CheckForDebugger()
{
__try
{
DebugBreak();
}
__except(GetExceptionCode() == EXCEPTION_BREAKPOINT ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
{
// No debugger is attached, so return FALSE
// and continue.
return FALSE;
}
return TRUE;
}
例外タイプが予期され、障害が発生しているアドレスがわかっている場合にのみ、例外フィルターから EXCEPTION_EXECUTE_HANDLER を返します。 既定の例外ハンドラーが予期しない例外タイプと障害のあるアドレスを処理できるようにする必要があります。
例 3
次の例は、入れ子になったハンドラーの相互作用を示しています。 RaiseException 関数は、例外ハンドラーの保護された本体内にある終了ハンドラーの保護された本文で例外を発生させます。 例外により、システムは FilterFunction 関数を評価し、その戻り値によって例外ハンドラーが呼び出されます。 ただし、例外ハンドラー ブロックが実行される前に、制御フローが終了ハンドラーの __try ブロックを残しているため、終了ハンドラーの __finally ブロックが実行されます。
DWORD FilterFunction()
{
printf("1 "); // printed first
return EXCEPTION_EXECUTE_HANDLER;
}
VOID main(VOID)
{
__try
{
__try
{
RaiseException(
1, // exception code
0, // continuable exception
0, NULL); // no arguments
}
__finally
{
printf("2 "); // this is printed second
}
}
__except ( FilterFunction() )
{
printf("3\n"); // this is printed last
}
}