【テクニカル・上級編】エラーハンドリングの極意:On Error GoTo 0とResume Nextの正しい使い分け – Excel VBA解析バイブル

スポンサーリンク

エラーハンドリングの極意:コードの「墓場」と「回廊」を制御せよ

VBAにおけるエラーハンドリングを「とりあえずの保険」と捉えているのであれば、今すぐその思考を捨てていただきたい。

我々が向き合っているのは、メモリ管理がブラックボックス化しがちなCOMオブジェクトの海であり、システム連携という名の「いつ落ちてもおかしくない不安定な回廊」だ。`On Error Resume Next`を多用してエラーを握り潰すのは、火災報知器の配線を切断して「火事がない」と主張するのと同じである。

真のエンジニアは、エラーを「無視」するのではなく、「制御可能なイベント」として設計に組み込む。

—

1. On Error Resume Next の「戦術的」運用

`On Error Resume Next`は、特定の処理(主にWindows API呼び出しや、存在するか不明なオブジェクトへのアクセス)においてのみ使用を許される「外科手術用メス」だ。

重要なのは、「無視した結果、何が起きるか」を予見できているかである。以下のコードを見てほしい。

‘ 悪い例:広範囲に適用し、状態異常を隠蔽する
On Error Resume Next
Set obj = GetObject(, “Excel.Application”)
‘ ここでエラーが起きても無視され、後続処理で「オブジェクト変数またはWithブロック変数が設定されていません」という追跡困難なエラーを誘発する

‘ 良い例:局所化し、即座に制御を戻す
Dim shell As Object
On Error Resume Next
Set shell = CreateObject(“WScript.Shell”)
On Error GoTo 0 ‘ 即座に無効化し、後続の予期せぬエラーを見逃さない

If shell Is Nothing Then
‘ ここで初めてログを出力し、異常終了する処理へ
Call WriteLog(“Critical: WScript.Shell could not be instantiated.”)
Exit Sub
End If

`On Error GoTo 0`は単なる停止命令ではない。「ここからは型通りの厳格な運用に戻る」という、コンパイラに対するエンジニアの宣誓である。

—

2. 堅牢なエラーハンドリングの設計:ログ出力とリソース解放

システムが肥大化すると、エラーハンドリングは「単なる分岐」から「状態管理」へと昇華する。特に、Excelのメモリリークを回避するためのオブジェクト解放は、エラー発生時こそ重要だ。

Public Sub ProcessSystemLinkage()
Dim ws As Worksheet
Dim objConn As Object ‘ 外部連携用オブジェクト

On Error GoTo ErrHandler

‘ 処理の開始
Set objConn = CreateObject(“ADODB.Connection”)
‘ …(ここにDB接続等の高負荷な処理)…

ExitProc:
‘ 正常時・異常時問わず必ず通る「リソース解放の回廊」
If Not objConn Is Nothing Then
objConn.Close
Set objConn = Nothing
End If
Exit Sub

ErrHandler:
‘ ログ出力と開発者への通知
Call WriteLog(“Error: ” & Err.Number & ” – ” & Err.Description)
‘ 開発環境ならデバッグを止めるが、本番なら安全に終了する等の判断
Resume ExitProc
End Sub

この「ExitProc」パターンは、VBAにおけるメモリ管理の黄金律だ。エラー発生時、スタックが積まれたまま関数を抜けると、メモリ上のCOMオブジェクトが解放されずに残り、それがExcelの「謎の重さ」や「突然のクラッシュ」の主因となる。

—

3. Windows APIとメモリの境界線

レガシーなシステム連携において、Windows APIを叩く際は「型」と「ポインタ」の管理が命綱だ。APIが失敗した際、`Err.LastDllError`を確認せずに次の処理へ進むのは自殺行為に近い。

‘ API呼び出しのラッパー例
Public Sub SafeAPICall()
Dim result As Long

result = SomeLegacyAPIFunction()

If result = 0 Then
‘ APIが失敗した場合、LastDllErrorで詳細を特定する
Dim errCode As Long
errCode = Err.LastDllError
Call WriteLog(“API Failed with Code: ” & errCode)
Err.Raise vbObjectError + 1000, “SafeAPICall”, “Critical System Failure”
End If
End Sub

—

結論:エラーは「設計の一部」である

シニアエンジニアとして最後に一つだけ伝えておく。

「完璧なコードは存在しない。しかし、完璧に制御されたエラー処理は存在する。」

エラーハンドリングを「後付けの修正」と考えるな。設計フェーズで「どこで、どのオブジェクトが、どんな理由で死ぬか」を書き出した時点で、そのシステムは半分完成している。

コードを記述する際、常に自問せよ。
「この行がエラーを吐いたとき、メモリは正しく解放されるか?」
「ログを見ただけで、現場の担当者はどこが悪いか即座に特定できるか?」

これらに対する解を持たないコードは、いずれ必ずシステムを崩壊させる。技術の真髄は、常に「最悪の事態」を想定した上で、いかに美しくリカバリを実装するかにある。VBAという限られた環境において、この哲学を貫くことこそが、伝説のアーキテクトへの第一歩だ。

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