【入門編】実務中級者向け:VB.NETアプリケーションにおける「Application.ThreadException」と「AppDomain.CurrentDomain.UnhandledException」によるグローバル例外捕捉基盤 – Visual Basic (VB / VB.NET)解析バイブル

スポンサーリンク

業務アプリの「最後の砦」を築く:VB.NETにおけるグローバル例外ハンドリングの真髄

こんにちは。現場で叩き上げられたVB.NETエンジニアの皆さん、あるいはVBAの世界から一歩踏み出し、堅牢なデスクトップアプリ構築を目指している皆さん。

業務アプリケーションを開発していると、必ずぶつかる壁があります。それは「想定外のエラー」です。どれだけ丁寧に `Try…Catch` を書いても、ネットワークの瞬断、OSの気まぐれ、あるいは未知のメモリリークが引き起こすクラッシュを100%防ぐことは不可能です。

「ソフトが突然消えた」「何をすればいいか分からない」というユーザーからの悲鳴を、ログと適切なフィードバックに変えるための「グローバル例外捕捉基盤」。これこそが、プロとアマを分かつ境界線です。今日は、その最終防衛ラインの構築法を伝授します。

1. なぜ「個別のTry…Catch」だけでは足りないのか?

VB.NETで開発を始めたばかりの頃は、全てのメソッドを `Try…Catch` で囲いたくなるかもしれません。しかし、それは「モグラ叩き」と同じです。

  • 開発者の盲点: 開発者が予期しなかった場所で発生するエラーは、Catchできません。
  • 非同期処理の闇: `Async/Await` を使った非同期処理の中で発生した例外は、通常の `Catch` をすり抜けてアプリケーション全体をクラッシュさせることがあります。

ここで登場するのが、.NETが提供する「2つの最終防衛ライン」です。

2. 2つの防衛ラインを理解する

VB.NETのデスクトップアプリ(Windows Forms等)には、主に2つの「捕獲場所」があります。

1. `Application.ThreadException`: UIスレッド(画面操作を行っているスレッド)で発生した例外をキャッチします。
2. `AppDomain.CurrentDomain.UnhandledException`: スレッドを問わず、プロセス全体で発生した「誰も拾わなかった例外」をキャッチします。

重要なポイント: この2つを両方実装することで、どんな場所で発生したエラーも漏らさない「網」を張ることができます。

3. 実践:最強の例外捕捉コード

それでは、実際に `Program.vb` (あるいは `Sub Main`) に組み込む実装例を見ていきましょう。

Imports System
Imports System.Windows.Forms
Imports System.Threading

Module Program

Sub Main()
‘ 1. UIスレッドの例外捕捉(Windows Forms用)
AddHandler Application.ThreadException, AddressOf Application_ThreadException

‘ 2. 全スレッド共通の例外捕捉(バックグラウンドスレッド等)
AddHandler AppDomain.CurrentDomain.UnhandledException, AddressOf CurrentDomain_UnhandledException

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

‘ UIスレッドで発生した例外を処理
Private Sub Application_ThreadException(sender As Object, e As ThreadExceptionEventArgs)
ShowErrorMessage(“UIスレッドで予期せぬエラーが発生しました。”, e.Exception)
End Sub

‘ それ以外のスレッドで発生した例外を処理
Private Sub CurrentDomain_UnhandledException(sender As Object, e As UnhandledExceptionEventArgs)
Dim ex As Exception = DirectCast(e.ExceptionObject, Exception)
ShowErrorMessage(“深刻なエラーが発生しました。アプリを終了します。”, ex)
End Sub

‘ ユーザーへの通知とログ記録の共通メソッド
Private Sub ShowErrorMessage(message As String, ex As Exception)
‘ ここでログファイルへの書き出しを行うのが定石です
‘ LogHelper.Write(ex.ToString())

MessageBox.Show(message & vbCrLf & vbCrLf & “詳細: ” & ex.Message,
“エラー”, MessageBoxButtons.OK, MessageBoxIcon.Error)

‘ 終了処理が必要であればここで行う
Environment.Exit(1)
End Sub
End Module

4. 現場で役立つ「極意」

コードを書くだけで満足してはいけません。実務で使う際には、以下の3点を必ず意識してください。

① ログには「例外の型」と「スタックトレース」を必ず入れる

単にエラーメッセージを表示するだけでは、デバッグは不可能です。`ex.ToString()` を使えば、例外の種類、メッセージ、そしてどこで発生したかのスタックトレースまで一括で取得できます。これをテキストファイルに吐き出すだけで、解析時間は劇的に短縮されます。

② ユーザーをパニックにさせない

エラーメッセージには、専門用語を並べないこと。「NullReferenceExceptionが発生しました」と言われてもユーザーは困ります。「データの読み込みに失敗しました。お手数ですが、保存して再起動してください」といった、次にどうすべきかを伝えるメッセージを心がけましょう。

③ 開発環境ではあえて「捕捉しない」

デバッグ中は、`Try…Catch` で握りつぶしてしまうと、どこでバグが起きたのか分かりづらくなります。開発時はこれらのハンドラを無効にするか、あるいは「デバッガがアタッチされている時は処理を飛ばす」という分岐を入れるのがプロの作法です。

最後に:ここをクリアすれば、あなたは一人前です

例外処理を制する者は、システムを制します。
最初は「こんなコード、本当に必要?」と思うかもしれません。しかし、一度でもユーザーのPCで謎のクラッシュが起きた時、手元に精緻なログファイルがあれば、あなたはヒーローになれます。

VB.NETの基本は、単なる文法ではありません。「どうすればシステムが壊れないか」「壊れた時にどうリカバリーするか」という設計思想そのものです。

この「最終防衛ライン」をあなたのアプリに組み込んでみてください。それだけで、あなたの書くプログラムの品格が、数段上のレベルに引き上げられますよ。

何か分からないことがあれば、いつでも聞いてくださいね。応援しています。

タイトルとURLをコピーしました