Word VBAを「兵器」に変える:堅牢なエラーハンドリングとログ基盤の設計論
Word VBAで業務自動化ツールを開発する際、多くのエンジニアが陥る罠がある。それは「エラーが出たら止まる」あるいは「デバッグ中だけ `MsgBox` でしのぐ」という場当たり的な実装だ。
いいか、業務効率化ツールとは、「放置されても正常に動き続けるもの」でなければならない。ユーザーはエラーが起きたとき、何が起きたのかを正確に報告してはくれない。だからこそ、システム側が「自らの死に様」を正確なログとして記録し、エンジニアに伝える仕組みが不可欠なのだ。
今日は、Word VBAを「おもちゃ」から「プロダクション級の業務ツール」へ昇華させる、エラーハンドリングの極意を伝授する。
—
1. なぜ「On Error GoTo 0」だけでは不十分なのか
初心者は `On Error Resume Next` を乱用し、エラーを握りつぶす。これは「病気を鎮痛剤で誤魔化す」のと同じで、根本的なバグを隠蔽する最悪のプラクティスだ。
堅牢なツールに求められるのは、「エラーの捕捉」「状態の記録」「安全な離脱」の3つである。これを実現するアーキテクチャが、すべてのプロシージャに共通する「エラーハンドラ構造」だ。
2. ログ出力の設計:ファイルI/Oの鉄則
エラーログをファイルに書き出す際、以下のルールを厳守せよ。
1. 排他制御を意識する: 同時に複数のWordドキュメントがログを書き込もうとすると、競合でツール自体がクラッシュする。ファイルを開いて書き込み、即座に閉じる(Open…Close)という「最小限の占有」を徹底せよ。
2. 追記モード(Append): 既存のログを破壊せず、常に末尾に追加すること。
3. 時刻とコンテキストの記録: 「いつ、どこで、何が起きたか」がなければログはゴミだ。
—
3. 実装:コピペで使える「エラーハンドリング・テンプレート」
以下は、私が大規模な文書自動生成システムで標準採用しているロギング基盤だ。これをモジュールに貼り付けて利用せよ。
Option Explicit
‘ ログファイルのパス(環境に合わせて変更すること)
Private Const LOG_FILE_PATH As String = “C:\Temp\Automation_Error.log”
”’
”’
Public Sub MainProcess()
On Error GoTo ErrorHandler
‘ ここに本来の業務ロジックを記述する
‘ 例: ActiveDocument.Tables(1).Cell(1, 1).Range.Text = “Test”
Exit Sub
ErrorHandler:
‘ エラー発生時の詳細をログに出力
WriteErrorLog Err.Number, Err.Description, “MainProcess”
‘ ユーザーへの通知(必要最小限に)
MsgBox “予期せぬエラーが発生しました。” & vbCrLf & _
“詳細はログファイルを確認してください: ” & LOG_FILE_PATH, vbCritical
End Sub
”’
”’
Private Sub WriteErrorLog(ByVal errNum As Long, ByVal errDesc As String, ByVal procName As String)
Dim fileNo As Integer
fileNo = FreeFile
On Error Resume Next ‘ ログ書き込み自体でエラーが出ても無限ループさせない
Open LOG_FILE_PATH For Append As #fileNo
Print #fileNo, “————————————————–”
Print #fileNo, “Timestamp: ” & Now
Print #fileNo, “Procedure: ” & procName
Print #fileNo, “Error No : ” & errNum
Print #fileNo, “Message : ” & errDesc
Close #fileNo
End Sub
このコードの「賢いポイント」
- `FreeFile` の使用: 既に開かれているファイル番号と重複しないよう、システムから安全な番号を動的に取得している。
- 二重エラー対策: `WriteErrorLog` 内に `On Error Resume Next` を置くことで、万が一ディスクがいっぱい等の理由でログ出力自体が失敗しても、Wordが強制終了するのを防いでいる。
—
4. プロフェッショナルへのアドバイス
このコードを実装するだけで、あなたのツールの品質は上位10%に入る。しかし、本当のプロはさらに一歩先を見ている。
- Rangeオブジェクトの解放: `Set rng = Nothing` を `Finally` 相当のラベル(ErrorHandlerの出口)に記述し、メモリリークを徹底的に防ぐこと。
- ログの肥大化対策: ログファイルが数MBを超えたら自動的にバックアップを取る、あるいは最新100件のみを残すようなローテーション機能を実装すると、管理コストが劇的に下がる。
最後に、エンジニアとしての信条を忘れないでほしい。
コードは書いた後が勝負だ。エラーを隠すな。エラーを「可視化」し、制御下に置くことこそが、自動化を成功させるための唯一の近道である。
さあ、あなたのツールを「止まらない、恐れない、信頼できる」プロダクトへ進化させよう。実装で躓くようなことがあれば、またいつでも聞きに来てくれ。
