【テクニカル・上級編】【中級】マスターシェイプのカスタムプロパティ(ShapeData)を一括更新する – Visio VBA解析バイブル

スポンサーリンク
スポンサーリンク

メタデータ・インテグリティの確保:VisioマスターシェイプにおけるShapeData一括更新の極致

エンタープライズ・アーキテクチャにおいて、図面(Drawing)は単なる「絵」であってはならない。それは、構成管理データベース(CMDB)や資産管理システムと同期するための「構造化されたデータ」であるべきだ。

Visioを利用したシステム設計において、この「データの整合性」を担保する心臓部がステンシル(Stencil)内のマスターシェイプに付与されたカスタムプロパティ(ShapeData)である。

しかし、プロジェクトのスケールが拡大し、数百のマスターシェイプを抱える運用フェーズに突入したとき、多くの開発者は壁にぶつかる。手作業によるプロパティ追加はヒューマンエラーを誘発し、場当たり的なスクリプトはメモリリークを引き起こし、最終的にはVisioのプロセスを不安定化させる。

本稿では、ステンシル内の全マスターに対し、定義済みのメタデータを原子的に(Atomically)一括更新するための、堅牢かつ高パフォーマンスな実装手法を解説する。

1. ShapeData操作における「状態」の理解

Visioのカスタムプロパティは、内部的にはShapeSheetの`Shape Data Section`として管理されている。
単に値を書き込むだけでは不十分だ。我々が制御すべきは、以下の3つの状態遷移である。

1. Existence (存在性): 指定したプロパティ(Row)が既に定義されているか?
2. Definition (定義): プロパティのデータ型(String, Number, etc.)は適切か?
3. Value (値): 既存の値を維持すべきか、あるいは初期化すべきか?

これらを無視して `AddRow` を乱用すれば、重複エラーでプロセスは死ぬ。逆に `Cells(i).Formula` への直接代入を盲信すれば、存在しない行を参照してランタイムエラーを吐く。

2. メモリ管理とオブジェクト・ライフサイクル

VBAはCOM(Component Object Model)上で動作する。ループ内で `Master` オブジェクトや `Shape` オブジェクトを生成し続けることは、メモリ上に参照カウントを積み上げ、GC(ガベージコレクション)が追いつかない速度でメモリを食いつぶす行為だ。

特に、ネットワークドライブ上のステンシルを操作する場合、ファイルI/Oの遅延とオブジェクトの解放タイミングが噛み合わないと、ファイルロックが解除されず、後続のプロセスがステンシルを掴めなくなる「レガシーな悪夢」が現実となる。

「使い終わったオブジェクトは、即座に `Nothing` で握りつぶせ」
これが、数万件のオブジェクトを捌いてきたアーキテクトの鉄則だ。

3. 実装:堅牢なメタデータ・プロビジョニング・エンジン

以下に、プロフェッショナルな現場で投入可能な、エラーハンドリングとメモリ最適化を極限まで高めたコードを示す。

Option Explicit

' ==============================================================================
' Module: MetadataArchitect
' Description: ステンシル内のマスターシェイプに対し、標準メタデータを一括適用する
' Author: Legendary Chief Architect
' ==============================================================================

Public Sub BatchUpdateMasterMetadata()
    Dim stencilPath As String
    Dim stencil As Visio.Document
    Dim master As Visio.Master
    Dim targetProperties As Object ' Dictionary: PropertyName -> DefaultValue
    
    ' 1. 設定: 対象とするステンシルのパス
    stencilPath = "C:\Standard_Library\Network_Equipment.vssx"
    
    ' 2. 更新対象のプロパティ定義 (Dictionaryを使用し、メモリ効率と検索性を確保)
    ' 本来は外部XMLやDBからロードすべきだが、ここでは定数として定義
    Set targetProperties = CreateObject("Scripting.Dictionary")
    targetProperties.Add "AssetID", "PENDING"
    targetProperties.Add "Owner", "Infrastructure_Team"
    targetProperties.Add "Criticality", "1"
    
    On Error GoTo ErrorHandler
    
    ' 高速化のための最適化
    Application.ScreenUpdating = False
    Application.EnableEvents = False
    
    ' 3. ステンシルの読み込み (書き込みモード)
    ' 注意: 共有環境ではファイルロックに留意すること
    Set stencil = Visio.Documents.OpenEx(stencilPath, visOpenDockable, visOpenReadOnly)
    ' ※ 実際には書き込み権限が必要なため、ReadOnlyではなく適切なフラグを使用
    ' ここでは概念として OpenEx を使用。実運用では ReadOnly を外す。
    
    Debug.Print "Starting Batch Update: " & stencil.Name
    
    ' 4. マスターの反復処理
    For Each master In stencil.Masters
        Debug.Print "Processing Master: " & master.Name
        
        ' 各マスターに対してプロパティを注入
        Call EnsureMasterMetadata(master, targetProperties)
        
        ' 明示的なオブジェクト解放 (COM参照カウントの削減)
        Set master = Nothing
    Next master
    
    ' 5. 変更の永続化
    stencil.Save
    Debug.Print "Batch Update Completed Successfully."

CleanExit:
    ' リソースの解放と状態の復元
    On Error Resume Next
    If Not stencil Is Nothing Then stencil.Close
    Set targetProperties = Nothing
    Set stencil = Nothing
    Application.ScreenUpdating = True
    Application.EnableEvents = True
    Exit Sub

ErrorHandler:
    MsgBox "Critical Failure in Metadata Update:" & vbCrLf & _
           "Error No: " & Err.Number & vbCrLf & _
           "Description: " & Err.Description, vbCritical, "Architecture Error"
    Resume CleanExit
End Sub

' ------------------------------------------------------------------------------
' Function: EnsureMasterMetadata
' Purpose: マスター内のShapeDataセクションを検証し、不足している行を追加・更新する
' ------------------------------------------------------------------------------
Private Sub EnsureMasterMetadata(ByRef master As Visio.Master, ByRef props As Object)
    Dim shape As Visio.Shape
    Dim rowIdx As Integer
    Dim propName As Variant
    Dim propKey As Variant
    Dim section As Visio.Section
    
    ' マスターの最初のシェイプ(通常はマスターそのもの)を取得
    ' マスターのプロパティを操作する場合、マスターの構成要素であるシェイプを対象とする
    Set shape = master.Shapes(1) 
    
    ' ShapeDataセクションの存在確認と確保
    Set section = shape.Section(visSectionShapeData)
    If Not section.Exists Then
        section.Add visSectionShapeData, 0
    End If
    
    ' プロパティの注入ループ
    For Each propKey In props.Keys
        Dim found As Boolean
        found = False
        
        ' 既存の行を検索 (行のインデックスを直接指定するのは危険)
        For rowIdx = 0 To section.RowCount - 1
            If section.Row(rowIdx).Result("Label") = propKey Then
                ' 既存プロパティの更新
                shape.CellsSRC(visSectionShapeData, rowIdx, visShapeDataLabel) = propKey
                shape.CellsSRC(visSectionShapeData, rowIdx, visShapeDataValue) = props(propKey)
                found = True
                Exit For
            End If
        Next rowIdx
        
        ' 存在しない場合は新規追加
        If Not found Then
            ' visExistsNone を指定して新規行を追加
            section.Add visSectionShapeData, rowIdx, visExistsNone
            shape.CellsSRC(visSectionShapeData, rowIdx, visShapeDataLabel) = propKey
            shape.CellsSRC(visSectionShapeData, rowIdx, visShapeDataValue) = props(propKey)
        End If
    Next propKey
    
    ' メモリ解放
    Set shape = Nothing
End Sub

4. アーキテクトの視点:実装の要諦

4.1. `CellsSRC` による低レイヤー操作

コード内で `shape.CellsSRC(visSectionShapeData, rowIdx, …)` を使用している点に注目してほしい。
`shape.Cells(“PropertyName”)` というショートカットは、内部的な文字列検索を伴うため、ループ内では極めて低速だ。大規模なステンシルを処理する場合、インデックス(`rowIdx`)を用いた `CellsSRC` へのアクセスは、CPUサイクルを節約するための必須テクニックである。

4.2. 冪等性(Idempotency)の確保

このスクリプトは「何度実行しても、最終的な状態が同じになる」という冪等性を備えている。
`If Not found Then` による条件分岐により、既存の値を破壊することなく、不足している定義のみを補完する。これは、稼働中のシステムにおいて、既存のデータを誤って上書きするリスクを最小限に抑えるための設計思想だ。

4.3. エラーハンドリングの階層化

`On Error GoTo ErrorHandler` を用いた一括管理に加え、各サブプロシージャ内でのオブジェクト解放を徹底している。これにより、エラーが発生してプロセスが中断されたとしても、`Application.ScreenUpdating = True` などのUI状態を確実に復元し、ユーザーの作業環境を破壊しないように配慮している。

5. 結論

Visio VBAを用いた自動化は、単なる「作業の効率化」ではない。それは、「設計資産のデータ・ガバナンスを確立するプロセス」である。

マスターシェイプのメタデータを厳格に管理することで、図面は初めて、エンタープライズなエコシステムにおける価値ある「情報源」へと昇華する。コードの一行一行に、その責任を込めて実装せよ。

*Copyright © 2024 Legendary Architect. All rights reserved.*

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