【Visio VBA】非表示ステンシルの安全な動的生成:メモリリークを根絶するリソース管理の極意
業務自動化の現場において、Visio VBAによるシェイプの動的生成や定型図面の自動構築は極めて強力な武器となる。しかし、実務で数千回・数万回のループ処理を伴うツールを構築した際、「なぜか処理が進むにつれてPCが重くなる」「Visioが突然フリーズする・落ちる」という壁にぶつかったことはないだろうか。
その原因の多くは、マスターシェイプを取得するために開いたステンシル(.vssx)の解放漏れ、そしてVisioの裏側で肥大化するオブジェクトのゾンビ化にある。
今回は、開発プロジェクトのリーダーである私から、ツール実行時のみステンシルをバックグラウンドで安全にロードし、処理完了と同時に確実にメモリから消し去る「プロダクション品質のライフサイクル管理パターン」を伝授しよう。
—
1. なぜ「なんとなく開いて閉じる」コードは破綻するのか?
多くの開発者がやりがちなアンチパターンを見てみよう。
‘ 【悪手】ありがちな脆弱なコード
Sub BadExample()
Dim stn As Visio.Document
Set stn = Documents.OpenEx(“C:\Templates\MyShapes.vssx”, visOpenDocked + visOpenRO)
‘ 何らかの処理
Dim shp As Visio.Shape
Set shp = ActivePage.Drop(stn.Masters(“ProcessNode”), 0, 0)
‘ 文書を閉じる(つもり)
stn.Close
‘ 完結していない!
End Sub
このコードには、実務の現場では致命傷となる3つの欠陥がある。
1. エラー時のメモリリーク: `Drop` メソッドなどで予期せぬ実行時エラーが発生した場合、`stn.Close` に到達せず、ステンシルがVisioのメモリ内に幽霊のように居座り続ける。
2. UI描画コストの発生: `visOpenDocked` などのフラグは、ユーザーインターフェース(UI)側に無駄な描画負荷やウィンドウ管理のオーバーヘッドを生む。
3. 参照の残存: `Document` 変数や `Master` 変数がスコープを抜けても、VBAの内部参照カウンタやVisioのグローバルコレクションが解放しきれないケースがある。
プロのエンジニアが目指すべきは、「例外が起ころうとも、100%確実にリソースをパージする堅牢な構造」である。
—
2. 解決策:完全非表示オープン & 確実なクリーンアップパターン
この問題を根本から解決するためには、以下の設計思想をコードに落とし込む必要がある。
- 完全バックグラウンド処理 (`visOpenHidden`): ユーザーの目に触れず、UIの描画ツリーにも載せないモードで開く。
- 構造化されたエラーハンドリング (`On Error Goto`): どの行で失敗しても、必ず終了処理(クローズ)を通る単一の出口(Single Exit Point)を作る。
- オブジェクトの明示的な破棄 (`Nothing` 代入): VBAのガベージコレクションを信用せず、コードの意志で参照を切断する。
—
3. 【コピペ即採用】プロダクションコード実装例
実務の現場でそのまま組み込める、堅牢性を極めたモジュールコードを提示する。このパターンをベースにしておけば、メモリリークのトラブルとは無縁でいられる。
Option Explicit
‘ =========================================================================
‘ 模範的プロシージャ:非表示ステンシルを安全に利用したシェイプ配置
‘ =========================================================================
Public Sub SafeCreateDiagramFromStencil()
Dim targetStencilPath As String
targetStencilPath = “C:\CorporateStandards\NetworkShapes.vssx” ‘ 実際のパスに変更してください
Dim vsoStencilDoc As Visio.Document
Set vsoStencilDoc = Nothing
‘ 1. エラーハンドリングの有効化(リソースリーク防止の要)
On Error GoTo ErrorHandler
‘ —————————————————————–
‘ Step A: ステンシルを「完全非表示・読み取り専用」でバックグラウンドオープン
‘ —————————————————————–
‘ visOpenHidden を使用することで、UI上のドッキングウィンドウ等に一切表示させず、
‘ メモリ上のドキュメントコレクションにのみロードします。
Set vsoStencilDoc = Application.Documents.OpenEx( _
targetStencilPath, _
visOpenHidden + visOpenRO _
)
‘ —————————————————————–
‘ Step B: 必要なマスターシェイプを取得して処理を実行
‘ —————————————————————–
Dim vsoMaster As Visio.Master
‘ マスター名が存在するかどうかの事前チェックを入れるとさらに堅牢になります
Set vsoMaster = vsoStencilDoc.Masters(“ServerNode”)
Dim vsoTargetPage As Visio.Page
Set vsoTargetPage = ActivePage
‘ 実際のドロップ処理
Dim vsoDroppedShape As Visio.Shape
Set vsoDroppedShape = vsoTargetPage.Drop(vsoMaster, 4.0, 5.0)
‘ プロパティの設定など…
vsoDroppedShape.Text = “Production Server 01”
‘ —————————————————————–
‘ Step C: 正常系クリーンアップ
‘ —————————————————————–
GoSub CleanUpResource
MsgBox “図形の生成が正常に完了しました。”, vbInformation, “処理成功”
Exit Sub
‘ =========================================================================
‘ 異常系・共通クリーンアップブロック
‘ =========================================================================
ErrorHandler:
MsgBox “エラーが発生しました: ” & Err.Description, vbCritical, “致命的なエラー”
GoSub CleanUpResource
Exit Sub
CleanUpResource:
‘ 2. 開いたドキュメントの確実なクローズ
On Error Resume Next ‘ クローズ時の二重エラーを防ぐ
If Not vsoStencilDoc Is Nothing Then
‘ visSaveNo を指定して、予期せぬ変更がステンシル側に保存されるのを完全に防止
vsoStencilDoc.Close
End If
On Error GoTo 0
‘ 3. オブジェクト変数の完全解放
Set vsoMaster = Nothing
Set vsoStencilDoc = Nothing
Set vsoDroppedShape = Nothing
Set vsoTargetPage = Nothing
Return
End Sub
—
4. チーフアーキテクトからの実践的なアドバイス
このパターンを実務の自動化ツールに組み込む際、さらに意識すべきポイントを共有しよう。
① データベースや外部ファイル連携時の注意点
もし、配置するシェイプの種類や数(座標・テキストなど)をExcelやSQLデータベースから動的に読み込むバッチ処理を組む場合、ループの内側で `Documents.OpenEx` を呼ぶのは絶対法度だ。
ファイルIOとドキュメントオブジェクトの生成コストは非常に重い。ステンシルは処理の開始時に一度だけ開き、ループを抜けるまでメモリ上に保持し続け、一連の処理が終わってから一括でクローズすること。
② パスはハードコーディングを避ける
プロダクション環境において、ステンシルファイルのパスをコード内に直書きするのは保守性を下げる。
`ThisDocument.Path & “\..\Stencils\MyShapes.vssx”` のように、アドインやマクロを格納している親フォルダーからの相対パスで解決する仕組みを取り入れることで、別環境(テスト環境から本番環境への移行など)でのファイルパス迷子を防ぐことができる。
—
総括
Visio VBAにおけるオブジェクト管理は、デスクトップアプリのネイティブメモリを直接叩いているという意識を持つことが何よりも重要である。
今回紹介した 「非表示オープン (`visOpenHidden`) + 確実な例外処理によるクローズ + 変数の明示的破棄」 の3原則をマスターすれば、何時間稼働させてもメモリ消費量が微動だにしない、極限まで洗練されたプロフェッショナルなツールを構築できるはずだ。
現場の信頼を勝ち取る堅牢なコードで、真の業務自動化を実現してほしい。
