Visioの深淵を覗く:ConnectedShapesによるトポロジ解析の極意
Visioの図面を単なる「絵」と見なしているうちは、君はまだ門前にすら立っていない。Visioの本質は「リレーショナル・データベースをGUIで可視化したもの」である。シェイプはレコードであり、コネクタはリレーション(外部キー)だ。
今回は、このデータ構造をプログラムから直接叩き、ネットワークトポロジを解析する。多くのエンジニアが`FromConnects`や`ToConnects`のプロパティを泥臭くループさせて時間を浪費しているが、真のアーキテクトは`ConnectedShapes`メソッドを使う。これが何を意味するか、理解を深めていこう。
—
1. なぜConnectedShapesを選ぶのか:計算量とメモリ管理
`visConnectedShapesIncomingNodes`や`visConnectedShapesOutgoingNodes`を使い分けることで、Visioは内部的な接続インデックスを直接参照する。自前で`Connects`コレクションをイテレーションする処理と比較すれば、その速度差は歴然だ。
特に数千個のシェイプからなる巨大図面において、オブジェクトの生成・破棄はメモリリークの最大の要因となる。VBAのガベージコレクションを信用してはならない。
- オブジェクトの明示的破棄: `Set obj = Nothing` は儀式ではない。循環参照を避けるための必須の防衛線だ。
- イベントの抑制: `Application.ScreenUpdating = False` は当然として、`Application.DeferRecalc = True` を適切に併用しなければ、解析中に再計算が走り、パフォーマンスは指数関数的に劣化する。
—
2. ネットワーク解析の実装:ConnectedShapesによる再帰的探索
以下に、特定のシェイプから下流のノードを再帰的に取得し、その構造を解析するプロトタイプを示す。
‘ 伝説的なトポロジ解析エンジン(プロトタイプ)
Public Sub AnalyzeTopology(ByVal startShape As Visio.Shape)
Dim connectedShapes() As Long
Dim i As Long
Dim targetShape As Visio.Shape
‘ 速度向上のための最適化
Application.DeferRecalc = True
‘ 接続されているシェイプのIDを高速取得
‘ visConnectedShapesOutgoingNodes: 下流方向のノードを取得
connectedShapes = startShape.ConnectedShapes(visConnectedShapesOutgoingNodes, “”)
For i = LBound(connectedShapes) To UBound(connectedShapes)
Set targetShape = ActivePage.Shapes.ItemFromID(connectedShapes(i))
‘ ここで解析ロジックを実装
Debug.Print “Found Node: ” & targetShape.Name & ” (ID: ” & targetShape.ID & “)”
‘ 再帰的な追跡(スタックオーバーフローに注意せよ)
AnalyzeTopology targetShape
‘ メモリの解放:ここを疎かにすると数千ノードでプロセスが死ぬ
Set targetShape = Nothing
Next i
Application.DeferRecalc = False
End Sub
—
3. レガシー環境とWindows APIの活用
現場のVisio環境は往々にして「負債」を抱えている。特に古いカスタムシェイプや、グループ化が複雑にネストされた図面では、`ConnectedShapes`が正確な値を返さないケースがある。
そのような場合、私は迷わず Windows API(User32.dll) を呼び出し、ウィンドウハンドル経由でVisioの描画コンテキストへ直接介入するか、あるいは`ShapeSheet`を直接操作して接続ポイントの座標を物理的に算出する。
‘ 必要に応じてAPIを用いて描画状態を強制リフレッシュする
Private Declare PtrSafe Sub Sleep Lib “kernel32” (ByVal dwMilliseconds As Long)
‘ 複雑な大規模図面では、Visioの描画完了を待つためにSleepを挟む泥臭い戦略も時には必要だ
—
4. シニアアーキテクトへの提言:設計の美学
君たちが解析したトポロジ情報は、XMLやJSONに出力して外部のDBへ流し込むべきだ。Visioはあくまで「可視化インターフェース」であり、データ構造の保存場所ではない。
1. 分離せよ: 図面ファイルと解析データ(トポロジの親子関係)を分けること。
2. 型を厳格にせよ: `Object`型で逃げるな。`Visio.Shape`、`Visio.Connect`、`Visio.Page`を厳格に型定義し、コンパイル時チェックの恩恵を受けろ。
3. 例外を握りつぶすな: `On Error Resume Next`を乱用するエンジニアは、アーキテクトとしては失格だ。予期せぬ接続断やID欠損に対して、どのようなフォールバックを行うか。そこがプロの分かれ目だ。
Visio VBAは古い言語だが、そのオブジェクトモデルは極めて洗練されている。このAPIを掌握することは、単なる自動化を超え、システムの「構造そのもの」をコントロールする力を手に入れることに他ならない。
次は、シェイプの`EventXFMod`をフックして、接続関係が変更された瞬間にリアルタイムでデータベースを更新する「イベント駆動型トポロジ同期」について語ろう。
君のコードが、図面という名の迷宮を解き明かす鍵になることを期待している。
