Word VBAの深淵:『Compareメソッド』を制御し、文書比較エンジンを極限まで最適化する
Word VBAにおいて、`Document.Compare`メソッドは「魔法の杖」のように見えるかもしれない。だが、このAPIを無策に呼び出せば、メモリリークの温床となり、巨大な文書を扱う際には即座にアプリケーションのハングアップを招く。
本稿では、単なる自動化ツールを超えた、プロフェッショナルな「文書比較エンジン」の設計思想を伝授する。
—
1. オブジェクトモデルの罠と「Range」の生存戦略
Word VBAで最も誤解されているのは、`Document`と`Range`のライフサイクルだ。`Compare`メソッドを実行すると、Wordは裏で「比較用の一時文書」を生成する。この挙動を理解していないと、COMオブジェクトがメモリ上に残留し、Wordのインスタンスがゾンビ化する。
極意: `Compare`の結果は、必ず個別のドキュメントオブジェクトとして明示的に捕捉し、処理終了後に`SaveChanges:=wdDoNotSaveChanges`で破棄せよ。
2. 高度な差分抽出エンジンの設計
単純に比較するだけなら`Compare`を叩いて終わりだが、実務で求められるのは「どの箇所が、どう変わったか」の構造化データだ。以下のコードは、差分をハイライトしつつ、その情報を抽出する堅牢な実装モデルである。
‘ 伝説的な比較エンジン:リソースを極限まで最適化する
Public Sub ExecuteAdvancedComparison(ByVal pathOriginal As String, ByVal pathRevised As String)
Dim docOriginal As Document
Dim docRevised As Document
Dim docResult As Document
Dim rng As Range
‘ オブジェクトの明示的生成
Set docOriginal = Documents.Open(pathOriginal, ReadOnly:=True)
Set docRevised = Documents.Open(pathRevised, ReadOnly:=True)
‘ 比較の実行:結果を新しい文書へ出力する
‘ Compareメソッドはバックグラウンドで一時的なDOMを構築する。
‘ 巨大な文書の場合、ここでメモリ消費がスパイクするため注意が必要。
Set docResult = Application.CompareDocuments( _
OriginalDocument:=docOriginal, _
RevisedDocument:=docRevised, _
Destination:=wdCompareDestinationNew)
‘ 差分箇所の走査とハイライト処理
‘ Revisionオブジェクトを直接操作することで、変更箇所を特定する
Call HighlightAndReportRevisions(docResult)
‘ 明示的なクリーンアップ
docOriginal.Close SaveChanges:=wdDoNotSaveChanges
docRevised.Close SaveChanges:=wdDoNotSaveChanges
Set docOriginal = Nothing
Set docRevised = Nothing
Set docResult = Nothing
End Sub
Private Sub HighlightAndReportRevisions(ByRef targetDoc As Document)
Dim rev As Revision
For Each rev In targetDoc.Revisions
‘ Rangeオブジェクトの生存期間を最小化する
With rev.Range
.HighlightColorIndex = wdYellow
‘ ここで必要に応じて外部ログやDBへ差分情報をエクスポートする
Debug.Print “ChangeType: ” & rev.Type & ” | Text: ” & .Text
End With
Next rev
End Sub
—
3. パフォーマンスと安定性を担保する「極限の知見」
Windows APIによる「応答なし」の回避
大規模な比較処理中、WordはUIスレッドを占有する。これを防ぐために、長時間処理の合間に `DoEvents` を挟むか、あるいは外部プロセス(C#で作成したライブラリ)に計算負荷を逃がし、COM経由で結果だけを受け取るアーキテクチャが推奨される。
レガシー環境でのメモリ最適化
VBAのメモリ管理は信頼性に欠ける。特にWord 2010以前の環境では、`Garbage Collection`を待つのではなく、以下の手法で強制的にリソースを回収せよ。
- Rangeオブジェクトの再利用: ループ内で`New`を多用せず、既存のRangeの`SetRange`メソッドを使用してメモリ領域を再定義せよ。
- イベントの無効化: `Application.ScreenUpdating = False` は必須だが、比較プロセス中は `Application.DisplayAlerts = wdAlertsNone` を併用し、予期せぬダイアログによる停止を完全に排除せよ。
—
4. アーキテクトの視点:なぜVBAなのか
現代の視点で見れば、比較アルゴリズムをPythonの`difflib`等で行う方が賢明に見えるかもしれない。しかし、「Wordの変更履歴エンジンそのものが持つ、レイアウトを保持した差分アルゴリズム」を再現することは、サードパーティライブラリには不可能だ。
我々がWord VBAでツールを作る意味は、Wordという閉じたエコシステムの「真の挙動」をハックし、ビジネスロジックに統合することにある。
このコードをベースに、さらに「変更者」や「変更日時」をメタデータとして抽出し、Excelへマッピングする機能を実装すれば、それは単なるマクロではなく、企業の監査に耐えうる「文書管理システム」へと昇華するはずだ。
コードを信じるな、オブジェクトの背後にあるメモリの状態を信じろ。それが、この領域を制する者の視座である。
