Windows Forms (.NET 1.1) での例外処理
GDNJ の Application.RunとExceptionのCatch より、知らなくても困らない補足。
Windows Forms アプリケーションのウィンドウズメッセージディスパッチャは、メッセージディスパッチ中にハンドルされない例外を受け取ると、次の3点を確認する。
この3点のうちどれかが真である場合、メッセージディスパッチャは例外に対して何も処理せず上位の例外ハンドラへと制御を返す。*1 そして、すべてが偽である場合は System.Windows.Forms.ThreadExceptionDialog が表示される。
Application.ThreadException
まず、Application.ThreadException だが、このイベントは現在スレッドの ThreadContext.ThreadException へ簡単にアクセスするための手段でしかないため、異なるスレッドから参照すると異なる結果になるということに注意しましょう。そして、Windows Forms のフレームワークでは、前述のすべての条件の確認をすべてのスレッドで通して1度だけしか行わないという点に非常に注意しなければならない。
System.Windows.Forms の内部処理が1度でもこのチェックを済ましてしまうと、以降 ThreadException イベントにハンドラを設定しても手遅れであること、複数の UI スレッドを構築する場合、最初にソコにアクセスしたスレッドが Application.ThreadException を設定していなければ、別のスレッドで正しく Application.ThreadException を設定していても無駄である、ということ。これは下手をするとハマります。
デバッガはアタッチされているか?
System.Diagnostics.Debugger.IsAttached と同様に、Managed Debugger がアタッチされているかどうかが判断基準となる。Win32 Native Debugger をアタッチしてもデバッガはアタッチされていないと判断される。
デバッグ可能なアセンブリをデバッグすることを許可された環境で動かしているか?
デバッグ可能な環境であるかどうかは、.NET Framework では2箇所の設定場所があります。1つはレジストリの HKLM\Software\Microsoft\.NETFramework であり、.NET Framework 開発者ガイドによると、
- 値が 0 の場合は、メッセージ ボックスを表示してユーザーの確認を求めます。
- 値が 1 の場合は、制御が戻されます。この結果、スタック ダンプが作成され、プロセスが終了します。
- 値が 2 の場合は、DbgManagedDebugger レジストリ キーに登録されているデバッガを呼び出します。
となっていますが、この場合に重要なことはデバッグが可能かどうかですので、設定値が 1 でなければデバッグ可能な環境であると判断されることになります。また、アプリケーション構成ファイルにて、System.Windows.Forms セクションに jitDebugging というキーがあり、この値が true であることも必要な条件に含まれます。*2
デバッグ可能なアセンブリであるかどうかという判断は、アセンブリの DebuggableAttribute 属性によって判断されるようで、C# あればコンパイル時に /debug+ によってデバッグ可能であるとマーキングすることができます。