更新 : 2007 年 11 月
例外通知は、すべての通知の中で最も説明が難しく、理解しにくい通知です。ここでは、例外処理と、プロファイル API がさまざまな種類の例外を処理する方法について説明します。
例外通知のフロー チャート
例外処理は、本質的に複雑です。ここで説明する例外通知は、高度なプロファイラが、パス (検索フェーズまたはアンワインド フェーズ)、フレーム、filter、およびプロファイリングされるプロセスの各スレッドに対して実行される finally ブロックを追跡するために必要とする情報をすべて提供します。例外通知では ThreadID は通知されませんが、ICorProfilerInfo::GetCurrentThreadID メソッドを呼び出して、どのマネージ スレッドが例外をスローしたかを調べることができます。
次の図は、コード プロファイラが例外イベントを監視する際にさまざまなコールバックをどのように受け取るかを示しています。各スレッドは、通常の実行状態で開始されます。スレッドは、(検索フェーズまたはアンワインド フェーズで) 例外システム内の状態になると、例外システムによって制御されます。スレッドがこれらのいずれかの状態にある間に発生する、例外関連ではないコールバック (ICorProfilerCallback::ObjectAllocated など) は、例外システム自体によって発生したものです。例外システム以外の状態にあるスレッドは、任意のマネージ コードを実行しています。
例外のコールバックのシーケンス
入れ子になった例外
例外の処理中にマネージ コードを実行していたスレッドが別の例外をスローし、その結果、例外処理の完全な新しいパスが生成されることがあります(この新しいパスは、前の図で "新しい例外処理パス" と示されています)。そのような入れ子になった例外が元の例外の filter/finally/catch ブロックをエスケープすると、元の例外に次のような影響を及ぼす可能性があります。
入れ子になった例外が filter ブロック内で発生し、filter ブロックをエスケープすると、filter は false を返すと見なされ、最初のパスが続行されます。
入れ子になった例外が finally ブロック内で発生し、finally ブロックをエスケープすると、元の例外の処理は再開されません。
入れ子になった例外が catch ブロック内で発生し、catch ブロックをエスケープすると、元の例外の処理は再開されません。
アンマネージ ハンドラ
アンマネージ コードでも、例外を処理できます。この場合、プロファイラはアンワインド フェーズを監視しますが、catch ハンドラの通知は受け取りません。単に、アンマネージ コードで実行が正常に再開されます。アンマネージ コードを認識するプロファイラはこの状況を検出できますが、マネージ コードのみのプロファイラは、次のものを含む (ただし、これだけに限定されない) いくつかのものを検出します。
アンマネージ コードがマネージ コードを呼び出すか、マネージ コードに戻る場合、ICorProfilerCallback::UnmanagedToManagedTransition コールバック。
スレッドの終了 (アンマネージ コードがスレッドの根幹となっていた場合)。
アプリケーションの終了 (アンマネージ コードによってアプリケーションが終了した場合)。
CLR ハンドラ
共通言語ランタイム (CLR: Common Language Runtime) 自体によって例外を処理することもできます。この場合、プロファイラはアンワインド フェーズを監視しますが、catch ハンドラの通知は受け取りません。マネージ コードまたはアンマネージ コードで実行が正常に再開されるのを監視します。
未処理の例外
既定では、.NET Framework Version 2.0 で未処理の例外が発生すると、プロセスが強制終了されます。「マネージ スレッドの例外」で説明するように、アプリケーション互換性フラグを使用すると、.NET Framework Version 1 の例外ポリシーに強制的に従うことができます。