Visio自動化の暗部:バックグラウンドPDF変換における「メモリの呪縛」を解く
Visio VBAによる帳票生成やPDF変換を自動化している諸君なら、一度は直面したはずだ。数百、数千の図面をループ処理する際、処理が進むにつれて徐々に増大し、やがてVisioプロセスが力尽きてフリーズ、あるいは「メモリ不足」でクラッシュする現象。
巷のチュートリアルは「`Set obj = Nothing` を呼べ」と説くが、あれは気休めに過ぎない。VisioのCOMオートメーションにおいて、メモリリークの正体は「解放されない非可視インスタンスの肥大化」と「COMインターフェースの不完全なクリーンアップ」にある。
今日は、現場で生き残るための「プロセス制御」と「メモリ管理」の極限解法を伝授する。
—
1. なぜ「Close」だけでは足りないのか
VBAで `VisioApp.Quit` を呼び出しても、Windowsのタスクマネージャーを見るとプロセスが残存していることがある。これは、DOM(Document Object Model)の参照がどこかに残っているか、VisioがバックグラウンドでCOMイベントを処理し続けているためだ。
この「ゾンビプロセス」が蓄積することで、システムのリソースは食い潰される。大量処理を行う際、「Visioを起動しっぱなしにする」という設計思想そのものが、そもそも誤りであると断言する。
—
2. 実践:高信頼性PDF変換アーキテクチャ
メモリを安定させる唯一の解は、「一定数処理したらプロセスを強制再起動する」ことだ。また、UIの非表示化には `Application.Visible = False` を使うが、これだけでは不十分なケースがあるため、Windows APIを用いて確実にウィンドウを隠蔽する。
安定稼働のためのVBA実装例
Option Explicit
‘ メモリ監視と再起動を行うラッパー
Private Const MAX_DOCUMENTS As Long = 50 ‘ プロセス再起動のしきい値
Public Sub BatchExportToPDF(fileList As Collection)
Dim i As Long, count As Long
Dim visApp As Visio.Application
count = 0
For i = 1 To fileList.Count
‘ プロセスが未起動、または閾値到達で再起動
If visApp Is Nothing Or count >= MAX_DOCUMENTS Then
Call TerminateVisio(visApp)
Set visApp = CreateObject(“Visio.Application”)
visApp.Visible = False
visApp.AlertResponse = 7 ‘ ダイアログを自動的に閉じる
count = 0
End If
Call ExportSinglePDF(visApp, fileList(i))
count = count + 1
Next i
Call TerminateVisio(visApp)
End Sub
Private Sub ExportSinglePDF(app As Visio.Application, filePath As String)
Dim doc As Visio.Document
Set doc = app.Documents.Open(filePath)
‘ PDF出力処理
‘ 固定パス・ファイル名で出力
doc.ExportAsFixedFormat visFixedFormatPDF, Replace(filePath, “.vsdx”, “.pdf”)
‘ 明示的なドキュメント解放
doc.Close
Set doc = Nothing
‘ ガベージコレクションを促す(VBAでは限定的だが気休めではない)
DoEvents
End Sub
‘ プロセスを確実に抹殺するためのラッパー
Private Sub TerminateVisio(ByRef app As Visio.Application)
If Not app Is Nothing Then
app.Quit
Set app = Nothing
End If
‘ 念のため、実行中のVisioプロセスを強制終了するコマンド
Shell “taskkill /f /im visio.exe”, vbHide
End Sub
—
3. シニアエンジニアが知るべき「更なる深淵」
A. `AlertResponse` の徹底管理
バックグラウンド処理において最も恐ろしいのは、予期せぬエラーダイアログや「フォントがありません」といった警告でプロセスが停止することだ。`app.AlertResponse = 7` を設定することで、Visioは「No」を選択し続け、処理を中断させない。
B. COM参照の完全な遮断
`DoEvents` は、シングルスレッドであるVBAにおいて、OSにコントロールを戻し、COMの解放要求を処理させるための呼吸だ。ループの終端で必ず呼ぶこと。これを怠ると、Visual Studioのデバッガですら追えないメモリリークの温床となる。
C. なぜ「プロセス再起動」が最適解なのか
Visioというアプリケーションは、描画エンジンやキャッシュ機構が非常に重厚である。長時間稼働させると、ドキュメントを閉じた後でも「UNDO履歴」や「内部キャッシュ」がメモリに残留しやすい。これを物理的に「殺して再起動する」ことは、泥臭いが、長時間のバッチ処理における最も確実な「メモリ・リセット」である。
—
結論:システムは「壊れること」を前提に組め
諸君が構築すべきなのは「メモリリークしない完璧なコード」ではない。「メモリリークが発生しても、プロセスを再起動することでシステムが止まらないタフなアーキテクチャ」である。
リソースを使い切るまで粘るシステムは、いずれ必ず死ぬ。リソースを使い切る前に自ら身を引く(再起動する)システムこそが、エンタープライズの現場で生き残る真の自動化エンジニアの仕事だ。
さあ、Visioのプロセスを管理下に置き、その挙動を支配せよ。
