TIL

Today I Learned. 知ったこと、学んだことを書いていく

集約例外ハンドラを使ってみた - VB.NET

  • エントリポイントについてはここに書いた
  • VB.NETでの例外処理についてはここに書いた

アプリケーションフレームワークを無効にしてしまうと、My.Application.ApplicationContextが使えなくなるため、ApplicationEventsを使う方法がいいかも。My.Application.ApplicationContextはMainFormを入れ替えるときに使うから無効にしたくないときとか。

ApplicationEventsにUnhandledExceptionを追加し、集約例外ハンドラを実装

プロジェクトのプロパティ > アプリケーション > アプリケーションイベントの表示 をクリックするとApplicationEvents.vbが表示される。Application.vbを以下のように編集する

Imports Microsoft.VisualBasic.ApplicationServices

Namespace My
    ' 次のイベントは MyApplication に対して利用できます:
    ' Startup:アプリケーションが開始されたとき、スタートアップ フォームが作成される前に発生します。
    ' Shutdown:アプリケーション フォームがすべて閉じられた後に発生します。このイベントは、アプリケーションが異常終了したときには発生しません。
    ' UnhandledException:ハンドルされない例外がアプリケーションで発生したときに発生します。
    ' StartupNextInstance:単一インスタンス アプリケーションが起動され、それが既にアクティブであるときに発生します。 
    ' NetworkAvailabilityChanged:ネットワーク接続が接続されたとき、または切断されたときに発生します。
    Partial Friend Class MyApplication

        Private Sub MyApplication_UnhandledException(sender As Object, e As UnhandledExceptionEventArgs) Handles Me.UnhandledException
            MessageBox.Show("致命的なエラーが発生しました。" & vbLf & "システム担当者にご連絡ください。",
                            "エラー",
                            MessageBoxButtons.OK,
                            MessageBoxIcon.Error)
            ' ここはLog4netとか使うのかな
            Debug.Print(e.Exception.Message)
            Debug.Print(e.Exception.StackTrace)

        End Sub
    End Class
End Namespace

UngandledExceptionが発生したら、アプリケーションは終了してしまうが、それはしょうがない...

エントリポイントを作成し、Application.ThreadExceptionを追加し、集約例外ハンドラを実装

補足されていない例外をキャッチするにはApplication.ThreadExceptionイベントでキャッチできる。

エントリポイント(Main())を記述したモジュールをスタートアップオブジェクトに設定することで集約例外ハンドラを使える。

Module EntryPoint
    <STAThread()>
    Sub Main()
        ' UIスレッドの集約例外ハンドラ
        AddHandler Application.ThreadException, AddressOf Application_ThreadException
        ' UIスレッド以外の集約例外ハンドラ
        AddHandler AppDomain.CurrentDomain.UnhandledException,
            AddressOf CurrentDomain_UnhandledException

        Application.EnableVisualStyles()
        Application.SetCompatibleTextRenderingDefault(False)
        Application.Run(New Form1())
    End Sub

    ''' <summary>
    ''' UIスレッドの集約例外ハンドラ。
    ''' </summary>
    Sub Application_ThreadException(sender As Object, e As System.Threading.ThreadExceptionEventArgs)
        MessageBox.Show("致命的なエラーが発生しました。" & vbLf & "システム担当者にご連絡ください。",
                        "エラー",
                        MessageBoxButtons.OK,
                        MessageBoxIcon.Error)

        Debug.Print(e.Exception.Message)
        Debug.Print(e.Exception.StackTrace)

    End Sub

    ''' <summary>
    ''' UIスレッド以外の集約例外ハンドラ。
    ''' UnhandledException はアプリケーションが終了することを防止できない。
    ''' </summary>
    Sub CurrentDomain_UnhandledException(sender As Object, e As UnhandledExceptionEventArgs)
        MessageBox.Show("致命的なエラーが発生しました。" & vbLf & "システム担当者にご連絡ください。",
                        "エラー",
                        MessageBoxButtons.OK,
                        MessageBoxIcon.Error)

        Debug.Print(CType(e.ExceptionObject, Exception).Message)
        Debug.Print(CType(e.ExceptionObject, Exception).StackTrace)

        Environment.Exit(-1)
    End Sub
End Module

参考文献