Visio VBAを掌握せよ:メモリリークを許さない「超堅牢」なファイル一括処理の設計思想
Visio VBAで「フォルダ内の全図面からカスタムプロパティを抜き出す」というタスクは、自動化の登竜門です。しかし、多くのエンジニアがここで躓きます。「なぜか20ファイル目で固まる」「終了後もバックグラウンドにVisioが残る」――これらは単なるコードの不備ではなく、Visioのオブジェクト・ライフサイクルに対する理解不足が招く必然的な破綻です。
今回は、プロフェッショナルとして恥ずかしくない、堅牢で再利用性の高いバッチ処理の構築術を伝授します。
—
1. 陥りがちな罠:オブジェクト参照の放置
VBAにおいて `Set doc = Documents.Open(…)` を繰り返す際、最も恐ろしいのは「見えないゾンビプロセス」です。
- 参照のクリア: `Set doc = Nothing` を忘れると、ガベージコレクションが適切に機能せず、メモリ上にVisioのインスタンスが漂い続けます。
- イベントの干渉: 大量処理中にVisioの「保存しますか?」ダイアログが出ることは、バッチ処理における最大の汚点です。`Application.AlertResponse` を適切に制御し、常に静寂な環境で処理を回す必要があります。
—
2. 実践:高信頼性バッチ抽出スクリプト
このコードは、単に動くだけでなく、エラーハンドリングとリソース解放を徹底したプロダクションレベルの構造です。
Option Explicit
‘ — メイン処理 —
Sub ExportCustomPropertiesToCSV()
Dim fso As Object
Dim folder As Object
Dim file As Object
Dim targetPath As String: targetPath = “C:\VisioExports\Data.csv”
Set fso = CreateObject(“Scripting.FileSystemObject”)
Set folder = fso.GetFolder(“C:\SourceVSDX”)
‘ CSVのヘッダー書き込み
Dim csvFile As Object
Set csvFile = fso.CreateTextFile(targetPath, True)
csvFile.WriteLine “FileName,ShapeName,PropName,Value”
‘ 警告ダイアログを自動応答(0 = キャンセル等のデフォルト動作を回避)
Application.AlertResponse = 7 ‘ IDOKに相当
For Each file In folder.Files
If LCase(fso.GetExtensionName(file.Path)) = “vsdx” Then
ProcessVisioFile file.Path, csvFile
End If
Next
csvFile.Close
Application.AlertResponse = 0
MsgBox “全ファイルの抽出が完了しました。”, vbInformation
End Sub
‘ — 個別ファイル処理 —
Private Sub ProcessVisioFile(filePath As String, csvFile As Object)
Dim doc As Visio.Document
Dim pg As Visio.Page
Dim shp As Visio.Shape
Dim prop As Visio.Cell
‘ オブジェクトの開放を確実にするため、On Error GoToを使用
On Error Resume Next
Set doc = Application.Documents.Open(filePath)
If doc Is Nothing Then Exit Sub
For Each pg In doc.Pages
For Each shp In pg.Shapes
‘ カスタムプロパティ(ShapeSheet)の探索
If shp.SectionExists(visSectionProp, True) Then
Dim i As Integer
For i = 0 To shp.RowCount(visSectionProp) – 1
csvFile.WriteLine doc.Name & “,” & shp.Name & “,” & _
shp.CellsSRC(visSectionProp, i, visCustPropsValue).NameU & “,” & _
shp.CellsSRC(visSectionProp, i, visCustPropsValue).ResultStr(“”)
Next i
End If
Next shp
Next pg
‘ 処理終了後、即座に閉じてメモリを解放
doc.Close
Set doc = Nothing
On Error GoTo 0
End Sub
—
3. なぜこの設計なのか?(アーキテクトの視点)
① `AlertResponse` の制御
Visioはファイルを開く際、リンク切れや古い形式の警告を出すことがあります。これを放置すると、夜間バッチで朝出社した際に「ダイアログで止まっていた」という絶望的な事態になります。`AlertResponse` を設定し、自動的に「No」または「キャンセル」を選択させるのが定石です。
② `On Error Resume Next` の限定的使用
本来は避けるべきですが、ファイルI/Oにおいては「特定のファイルが壊れている」という理由で全行程が停止するのを防ぐため、最小限のスコープで利用します。ただし、必ず直後にエラーチェックを入れるのが流儀です。
③ `CellsSRC` の採用
`shp.Cells(“Prop.xxx”)` と記述する方法もありますが、プロパティ名が不明な場合や動的に取得したい場合は、`CellsSRC` インデックスアクセスが最も高速で安定します。文字列検索によるオーバーヘッドを排除できるからです。
—
4. 最後に:エンジニアへの提言
Visio VBAは古い言語仕様ですが、そのオブジェクトモデルは極めて強力です。今回紹介した「開く→処理→閉じる→解放」のサイクルを骨格として守り続ければ、数千ファイルを扱うような過酷な環境でも、あなたのツールは決して裏切ることはありません。
自動化の本質は「コードを書くこと」ではなく、「システムを無人化し、信頼を構築すること」にあります。まずはこのコードをベースに、あなたの業務に合わせてカスタマイズしてみてください。
何か技術的な壁にぶつかったら、また聞きに来なさい。その時は、さらに深いメモリ管理の領域まで案内しましょう。
