Visio VBAの深淵:排他制御とメモリ管理の「極限」
業務自動化の現場において、Visioの図面ファイル(VSDX)は単なる図ではない。それは構造化されたデータであり、同時に「共有の罠」が仕掛けられた地雷原でもある。
「他者が開いている図面からデータを抜き出し、別名で保存する」。
このありふれた要件に、浅い実装で挑めば必ず痛い目を見る。VisioのCOMオブジェクトはメモリ管理に極めて無頓着で、不用意なインスタンス生成は即座にメモリリークとゾンビプロセスを招くからだ。
今回は、現場のシニアエンジニアが避けて通れない「読み取り専用オープンと排他回避」の真髄を解き明かす。
—
1. 「読み取り専用」という名の安全圏
まず、`Application.Documents.Open` の引数を正しく理解せねばならない。デフォルトの挙動に依存するのはアマチュアの所作だ。
‘ 読み取り専用で開き、イベントを抑制して高速化を図る
Public Sub OpenReadOnly(strPath As String)
Dim visApp As Visio.Application
Dim visDoc As Visio.Document
‘ Visioのイベントを一時的に停止して処理負荷を軽減
Set visApp = Application
visApp.AlertResponse = 0 ‘ ダイアログを自動応答(デフォルト選択)
‘ ReadOnly引数をTrueに設定
Set visDoc = visApp.Documents.OpenEx(strPath, visOpenRO + visOpenNoWorkspace)
‘ … データ抽出処理 …
‘ 閉じる際は変更の破棄を強制
visDoc.Close
Set visDoc = Nothing
End Sub
ここでの肝は `visOpenNoWorkspace` だ。ワークスペース情報を読み込まないことで、無駄なUI再描画とメモリ消費を抑制できる。大規模図面であれば、このフラグ一つで処理時間は数秒単位で変わる。
—
2. 別名保存における競合回避の「防波堤」
読み取り専用で開いたドキュメントを別名保存する際、最も恐ろしいのは「同名ファイルが既に存在する場合のダイアログ」だ。これをVBA側で制御できないと、UIがフリーズしたままバックグラウンドで処理が停止する。
我々は `FileSystemObject` と `Windows API` を駆使し、保存前に「静かな環境」を整える必要がある。
‘ 保存の競合を回避する堅牢なロジック
Private Sub SafeSaveAs(doc As Visio.Document, newPath As String)
Dim fso As Object
Set fso = CreateObject(“Scripting.FileSystemObject”)
‘ 保存先の排他チェック(簡易的なロック確認)
If fso.FileExists(newPath) Then
On Error Resume Next
‘ 一時的な変更を行ってファイルがロックされていないか確認
Dim f As Integer: f = FreeFile
Open newPath For Binary Access Write Lock Read Write As #f
If Err.Number <> 0 Then
Err.Raise vbObjectError + 1000, , “保存先は現在他プロセスで使用中です。”
End If
Close #f
On Error GoTo 0
‘ 存在する場合は削除(上書き保存のトラブルを避ける)
fso.DeleteFile newPath, True
End If
‘ 別名で保存
doc.SaveAsEx newPath, visSaveAsWS
End Sub
—
3. メモリ解放の「儀式」:オブジェクトの明示的破棄
VBAにおいて、`Set obj = Nothing` を書かないのは、レストランで食い逃げするのと同じだ。特にVisioの `Document` や `Page` オブジェクトは、参照カウントが複雑で、循環参照が起きやすい。
中級者から脱却するためのアーキテクチャは、「エラーハンドリングを包含した解放ルーチン」の徹底にある。
Public Sub MasterProcess(strSource As String, strDest As String)
Dim doc As Visio.Document
On Error GoTo Cleanup
Set doc = Application.Documents.OpenEx(strSource, visOpenRO)
‘ 処理ロジック…
Call SafeSaveAs(doc, strDest)
Cleanup:
‘ どんなエラーが発生しようとも、オブジェクトは確実に解放する
If Not doc Is Nothing Then
doc.Close
Set doc = Nothing
End If
If Err.Number <> 0 Then
Debug.Print “Critical Error: ” & Err.Description
End If
End Sub
—
4. チーフアーキテクトからの提言:環境の保守性
最後に、レガシー環境における教訓を一つ。
Visio VBAを社内システムとして運用する際、「Visioのバージョンアップ」は最大の脅威だ。オブジェクトライブラリの参照設定は、可能な限り「レイトバインディング」を選択することを推奨する。
`Dim doc As Object` として宣言し、`CreateObject(“Visio.Application”)` を利用すれば、Visio 2016からMicrosoft 365版まで、コードを書き換えることなく対応できる。
「動くコード」を書くのは新人だ。「止まらないコード」を書くのがエンジニアである。
排他制御、メモリリークの排除、そして将来的な環境変動への耐性。これらを備えたVisio自動化システムこそが、真に現場を救うアーキテクチャとなる。
健闘を祈る。貴殿のコードが、明日の業務の礎となることを信じている。
