【テクニカル・上級編】【中級者向け】読み取り専用で開いた図面から情報を抽出し、別名で保存する際の排他制御 – Visio VBA解析バイブル

スポンサーリンク

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自動化システムこそが、真に現場を救うアーキテクチャとなる。

健闘を祈る。貴殿のコードが、明日の業務の礎となることを信じている。

タイトルとURLをコピーしました