【テクニカル・上級編】Document.DocumentSheetのUserセクションを活用したドキュメントレベルのグローバル状態管理 – Visio VBA解析バイブル

スポンサーリンク

Visio VBAの「グローバル変数依存」を脱却せよ:DocumentSheetを駆使した永続的状態管理の極意

多くのVBAエンジニアは、アプリケーションの実行状態を管理するために、標準モジュールで `Public` 変数を乱用する。しかし、大規模なVisioアドインや複雑な図面処理システムを構築する際、それは技術的負債の第一歩だ。Visioがクラッシュし、メモリが解放された瞬間に、積み上げたグローバル変数は霧散する。

真のアーキテクトは「状態」をコードの中ではなく、データの中に置く。今回解説するのは、Visioの心臓部である `Document.DocumentSheet` の `User` セクションをハックし、ファイル完結型の堅牢なステート管理を行う手法だ。

なぜ `DocumentSheet` なのか?

Visioの `DocumentSheet` は、ドキュメント全体の設定を司る「隠されたマスターシート」である。ここに `User` セクションを作成することで、以下のメリットを享受できる。

1. 永続性: ファイルを保存すれば状態は保存される。VBAのメモリ領域外で生存する。
2. 配布性: 外部設定ファイル(INIやJSON)を別途配布する必要がない。図面ファイル一つでツール設定やログを保持できる。
3. 整合性: `Document` オブジェクトと運命を共にするため、別ファイルを開いた瞬間に設定が混ざるリスクがない。

実装:DocumentSheetへの安全なアクセスと書き込み

ただ値を書き込むだけでは素人だ。Visioの `Cell` オブジェクトは存在確認とセクションの生成を意識しなければならない。以下のコードは、プロフェッショナルが現場で使う「型安全」を意識した実装パターンである。

Option Explicit

‘ 状態管理用のキー定数
Private Const SECTION_NAME As String = “User”
Private Const ROW_NAME As String = “ToolConfig”

”’

”’ DocumentSheetのUserセクションに値を永続保存する
”’

Public Sub SetGlobalState(ByVal key As String, ByVal value As String)
Dim doc As Visio.Document
Dim shp As Visio.Shape
Dim cell As Visio.Cell

Set doc = ThisDocument ‘ または対象のドキュメントを指定
Set shp = doc.DocumentSheet

‘ Userセクションに該当行が存在するか確認し、なければ生成
If Not shp.CellExistsU(SECTION_NAME & “.” & key, False) Then
shp.AddNamedRow visSectionUser, key, visTagDefault
End If

Set cell = shp.Cells(SECTION_NAME & “.” & key)

‘ 数式として書き込む(文字列はダブルクォーテーションで括るのがVisioの作法)
cell.FormulaU = “””” & value & “”””

‘ オブジェクトの明示的解放(VBAのGCは信用しない)
Set cell = Nothing
Set shp = Nothing
Set doc = Nothing
End Sub

”’

”’ 永続保存された状態を取得する
”’

Public Function GetGlobalState(ByVal key As String) As String
Dim shp As Visio.Shape
Set shp = ThisDocument.DocumentSheet

If shp.CellExistsU(SECTION_NAME & “.” & key, True) Then
GetGlobalState = shp.Cells(SECTION_NAME & “.” & key).ResultStr(“”)
Else
GetGlobalState = “”
End If

Set shp = Nothing
End Function

アーキテクトの視点:パフォーマンスとメモリの最適化

上記のコードで重要なのは、`CellExistsU` を使用している点だ。`FormulaU` を呼び出すたびに `DocumentSheet` の再計算トリガーが引かれる可能性がある。大規模なループ内で頻繁に呼び出すべきではない。

  • バッファリング: ログや大量の状態更新を行う場合は、メモリ内で辞書オブジェクト(`Scripting.Dictionary`)を保持し、ドキュメントの `BeforeDocumentSave` イベントで一括書き込みを行うのが正解だ。
  • メモリリーク対策: VisioのオブジェクトモデルはCOMベースである。`Set obj = Nothing` を徹底するのは当然として、特に再帰呼び出しや複雑な階層を持つShape操作時には、`Global.Application` を直接触らず、プロシージャスコープで渡すこと。

レガシー環境との共存:Win32 APIの活用

もし、社内システム連携のために「現在のドキュメントの物理パス」や「プロセスID」を `User` セクションにキャッシュしたい場合、Windows APIと組み合わせることで、さらに精度の高い制御が可能になる。

例えば、`GetProcessId` を取得し、それを `DocumentSheet` に書き込んでおく。別プロセスからそのファイルが開かれた際、既に他のユーザーが特定のアクションを実行中かどうかを、ファイルロックとは別次元の「アプリケーション層」で判定できる。

結論:技術は「仕組み」に宿る

グローバル変数に頼る開発は、プログラムを「脆弱な生き物」にする。しかし、`DocumentSheet` を利用した状態管理は、プログラムを「データと共生する頑強なシステム」へと昇華させる。

Visioというプラットフォームは、古くからあるが、そのオブジェクトモデルの深淵はまだ掘り尽くされていない。次にあなたが構築するシステムでは、ぜひこの「ファイル完結型の永続アーキテクチャ」を導入してみてほしい。

コードは嘘をつかない。正しく設計されたオブジェクトモデルは、時を越えて保守し続けることが可能だ。それが、伝説的な自動化エンジニアの矜持である。

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