こんにちは!Word VBAの世界へようこそ。いつも業務自動化の設計や開発をサポートしている先輩エンジニアです。
「マクロの記録」を卒業し、自分でVBAのコードを書き始めると、誰もが必ずぶつかる大きな壁があります。それは「実行時エラー(Runtime Error)」です。
自分のPCでは完璧に動いたマクロが、同僚のPCではなぜかエラーで止まってしまう。あるいは、昨日まで動いていたのに、特定の文書を処理しようとした瞬間に「黄色いデバッグ画面」が出てフリーズする……。こうしたトラブルに直面したとき、あわてて画面を閉じてしまっては、原因究明は一向に進みません。
「プログラムに、どこで、なぜ機嫌を損ねたのかを自ら語ってもらう」
これこそが、プロの現場で必須とされる「エラーログ出力」の仕組みです。今回は、Word VBAの基本的なオブジェクトモデル(`Application` / `Document` / `Range`)をおさらいしつつ、FSO(FileSystemObject)を使ってエラーをテキストファイルに自動記録する、極めて実用的で保守性の高いエラーログ基盤の作り方を丁寧に解説します。
ここをクリアすれば、あなたのWord VBAの実力は「ただ動くマクロ」から「業務で安心して使えるシステム」へと劇的に進化しますよ。一歩ずつ、一緒に学んでいきましょう!
—
1. Word VBAの基礎:なぜExcelよりエラーが起きやすいのか?
コードを書く前に、まずはWord VBA特有の「オブジェクトモデル」について、頭の中を整理しておきましょう。ExcelとWordは、構造が根本的に異なります。
- Application: Wordというアプリケーション全体を指します。
- Document: 開いている「文書(ファイル)」そのものです。
- Range: 文書内の「特定の範囲(文字、段落、あるいは文書全体)」を指します。
Excelは「セル(Cell)」という明確なグリッド(格子)で区切られているため、場所の特定が容易です。しかし、Wordは「水のように流れるテキストの流れ(ストリーム)」です。
フォントサイズが変わったり、1行追加されたりするだけで、文字の位置(Range)はドンドンずれていきます。そのため、以下のような理由でエラー(例: `5941: 指定されたコレクションのメンバーは存在しません` など)が発生しやすいのです。
- 処理しようとした段落やテーブル(表)が、ドキュメント内に存在しなかった。
- ユーザーがマクロの実行中に、うっかり別の文書をクリックしてアクティブにしてしまった。
- 文書の末尾を超えて文字を書き込もうとした(Rangeの範囲外指定)。
こうした「予期せぬエラー」が起きたとき、ユーザーをパニックに陥らせず、裏側でそっと原因をファイルに書き残しておく仕組みが、これから作る「エラーロギング」です。
—
2. エラーログの心臓部:FSO(FileSystemObject)とは?
VBAからWindowsのファイルやフォルダーを自由自在に操るための強力な相棒、それが FSO(FileSystemObject) です。
通常、VBAの標準機能だけでテキストファイルを書き出そうとすると、`Open` ステートメントや `Print #` といった少し古い、気難しい命令を使う必要があります。しかし、FSOを使えば、直感的かつ安全にテキストファイルを作成し、エラーログを追記していくことができます。
参照設定は不要!「後期バインディング」を採用する理由
FSOを使うには2つの方法がありますが、今回は「後期バインディング(Late Binding)」という手法を使います。
Dim fso As Object
Set fso = CreateObject(“Scripting.FileSystemObject”)
この書き方をすると、事前の面倒な設定(参照設定)が不要になります。他の人のPCにマクロ付き文書を配った際にも、「参照不可エラー」でマクロ自体が起動しないというトラブルを未然に防ぐことができる、実践的なテクニックです。
—
3. 実践!エラーログ出力機能付きテンプレートコード
それでは、実際に動くコードを見てみましょう。
今回は、どのようなマクロにも組み込めるように、「メインの処理を行うマクロ(MainProcess)」と、「エラーが発生したときにログを書き出す共通サブプログラム(WriteErrorLog)」の2つに分けて綺麗に整理(モジュール化)しました。
標準モジュールを挿入し、以下のコードをそのままコピー&ペーストして試してみてください。
Option Explicit
‘ =================================================================
‘ メイン処理:Word文書の段落数をカウントしてテキストを挿入する
‘ =================================================================
Sub MainProcess()
On Error GoTo ErrorHandler ‘ エラーが発生したら「ErrorHandler」ラベルへジャンプする指示
Dim doc As Document
Set doc = ActiveDocument
‘ — [開発者への優しさ:エラー検証用のトラップ] —
‘ わざとエラーを発生させたい場合は、下のコメントアウトを解除してください。
‘ Err.Raise 1004, “MainProcess”, “テスト用のダミーエラーが発生しました。”
‘ ————————————————–
‘ 1. 安全のためにApplicationの状態を固定する
Application.ScreenUpdating = False ‘ 画面更新を停止(高速化とチラつき防止)
‘ 2. メインの処理(例:文書の先頭に本日の日付と段落数を書き込む)
Dim rng As Range
Set rng = doc.Paragraphs(1).Range
rng.InsertBefore “【自動処理実行日: ” & Format(Date, “YYYY/MM/DD”) & “】” & vbCrLf
‘ 処理が正常に完了したことをユーザーに伝える
MsgBox “処理が正常に完了しました!”, vbInformation, “成功”
CleanUp:
‘ 【超重要】正常終了時も、エラー発生時も、必ずここを通って後片付けをする
Application.ScreenUpdating = True
Set rng = Nothing
Set doc = Nothing
Exit Sub ‘ メイン処理をここで終了(これがないと下のErrorHandlerに突入してしまう)
ErrorHandler:
‘ エラーが発生した場合、このブロックが実行される
Dim errNumber As Long
Dim errDescription As String
Dim errSource As String
‘ エラー情報を変数に退避(ログ出力中に情報が上書きされるのを防ぐため)
errNumber = Err.Number
errDescription = Err.Description
errSource = Err.Source
‘ ユーザーには親切なメッセージを見せる(デバッグ画面は見せない)
MsgBox “申し訳ありません。マクロの実行中にエラーが発生しました。” & vbCrLf & _
“エラーの詳細はログファイルに記録されましたので、管理者にお問い合わせください。”, _
vbCritical, “エラー発生”
‘ 自作のエラーログ書き出しサブプログラムを呼び出す
Call WriteErrorLog(errNumber, errDescription, errSource, “MainProcess”)
‘ 後片付けの処理(CleanUp)へ合流する
Resume CleanUp
End Sub
‘ =================================================================
‘ エラーログ書き出しサブプログラム(FSOを活用した堅牢な共通モジュール)
‘ =================================================================
Private Sub WriteErrorLog(ByVal errNum As Long, ByVal errDesc As String, ByVal errSrc As String, ByVal procName As String)
Dim fso As Object
Dim logStream As Object
Dim logFolderPath As String
Dim logFilePath As String
Dim logMessage As String
On Error Resume Next ‘ ログ出力自体がエラーで落ちるのを防ぐ「絶対防御」
‘ 1. ログファイルの保存先を決定
‘ マクロを実行している文書と同じフォルダーに「ErrorLog」フォルダーを作ります
If ActiveDocument.Path = “” Then
‘ 文書が一度も保存されていない(新規文書)の場合は、デスクトップを代替にする
logFolderPath = CreateObject(“WScript.Shell”).SpecialFolders(“Desktop”)
Else
logFolderPath = ActiveDocument.Path
End If
logFilePath = logFolderPath & “\Macro_Error_Log.txt”
‘ 2. FSOオブジェクトの生成(後期バインディング)
Set fso = CreateObject(“Scripting.FileSystemObject”)
‘ 3. ログに書き出すメッセージの作成(日時、プログラム名、エラー詳細)
logMessage = “[” & Format(Now, “YYYY-MM-DD HH:NN:SS”) & “] ” & _
“Proc: ” & procName & ” | ” & _
“ErrNo: ” & errNum & ” | ” & _
“Desc: ” & errDesc & ” | ” & _
“Source: ” & errSrc
‘ 4. ファイルへの書き込み(追記モード)
‘ OpenTextFileの引数: (パス, 動作モード[8=追記], 新規作成有無[True=存在しなければ作成])
Set logStream = fso.OpenTextFile(logFilePath, 8, True)
‘ ログメッセージを1行書き出す
logStream.WriteLine logMessage
‘ 5. ファイルを確実に閉じてメモリを開放(オブジェクトのライフサイクル管理)
logStream.Close
Set logStream = Nothing
Set fso = Nothing
On Error GoTo 0 ‘ 絶対防御を解除
End Sub
—
4. プログラミング初学者が陥りやすい3つの「深い落とし穴」
この仕組みを実装するにあたり、多くの人がつまづくポイントを3つ、先輩としてあらかじめお伝えしておきますね。
① `Exit Sub` を忘れて、常にエラー処理が動いてしまう罠
VBAのコードは、上から下へと順番に流れていきます。
メイン処理の最後に `Exit Sub`(または `Exit Function`)を書き忘れると、プログラムが正常に終わったはずなのに、その下にある `ErrorHandler:` ラベル以降の処理までそのまま突き抜けて実行されてしまいます。
「処理は成功したのに、なぜかエラーメッセージが出る!」という場合は、ほぼ100%これが原因です。必ず `CleanUp:` の中で `Exit Sub` させる構造を徹底しましょう。
② 新規保存していない文書で実行するとパスが消滅する罠
コードの中で `ActiveDocument.Path` を使ってログファイルの保存先を決めています。しかし、Wordを開いて一度も保存していない「文書1」の状態でマクロを実行すると、`ActiveDocument.Path` は空文字(””)を返します。
そのままファイルを作成しようとすると、存在しないパスを指定したことになり、エラーログの出力処理そのものがエラーで強制終了してしまいます。
今回のサンプルコードでは、保存されていない場合は「デスクトップ」にログを逃がすという、プロレベルの「フォールバック(回避策)」をあらかじめ仕込んであります。
③ `On Error Resume Next` を魔法の呪文だと思って常用する罠
「エラーが出ても止まらないように、すべてのコードの先頭に `On Error Resume Next` を書いておこう!」
これは、非常に危険な誘惑です。これをやると、エラーが発生してもプログラムは何事もなかったかのように次の行に進んでしまいます。結果として、データが破損したり、意図しない場所が削除されたりしているのに「なぜか正常終了した」ように見えてしまい、バグの発見が不可能ですらあります。
`On Error Resume Next` は、今回のログ書き出し処理のように「極めて局所的で、かつエラーが起きても大勢に影響がないと分かっている1行」の直前だけで使い、終わったらすぐに `On Error GoTo 0` で解除するのが、プロフェッショナルの鉄則です。
—
まとめ:この仕組みを手にいれたあなたへ
お疲れ様でした!
今回作成したエラーログの仕組みは、Word VBAだけでなく、Excel VBAやAccess VBAなど、あらゆるOffice自動化の現場でそのまま応用できる「一生モノの武器」です。
【エラー発生時の美しい処理フロー】
[メイン処理でエラー発生]
↓
[ErrorHandlerへジャンプ]
↓
[ユーザーへは親切なダイアログを表示]
↓
[裏側でFSOが起動し、テキストファイルに詳細なエラー内容を追記(ログ化)]
↓
[CleanUpでメモリを綺麗に解放して安全に終了]
この美しい流れを作れるようになれば、あなたの作ったマクロを誰かに使ってもらうときの安心感は、これまでの100倍以上になります。同僚から「動かないんだけど!」と言われたときも、「じゃあ、そのフォルダーにできている `Macro_Error_Log.txt` を送ってもらえる?」とスマートに返答し、一瞬で原因を特定できるようになりますよ。
VBAの基本オブジェクトを理解し、エラーハンドリングを制する者は、業務自動化のすべてを制します。ここをクリアできれば、Word VBAの基本はバッチリです。自信を持って、次のステップへ進んでくださいね。
あなたの自動化ライフが、より快適で素晴らしいものになることを応援しています!
