【テクニカル・上級編】Shapeオブジェクトの基本:IDとNameの違いを理解して特定の図形を確実に取得する – Visio VBA解析バイブル

スポンサーリンク

Visio VBAを掌握する極限の知見:ShapeIDとName/NameUの完全分離統治

Visio VBAにおける自動化の成否は、突き詰めれば「いかにしてターゲットの`Shape`オブジェクトをミリ秒単位の確実性で把捉するか」の一点にかかっている。

レガシーな図面、度重なるコピー&ペースト、そして言語ロケールの差異。これらが交差する現場において、図形の識別子を誤ることは、システム全体の崩壊を意味する。今回は、`ShapeID`、`Name`、そして`NameU`の本質的な違いを解剖し、大規模図面や外部システム連携において破綻しない「確実な図形取得」のアーキテクチャを提示する。

1. 三つの識別子の正体とライフサイクル

Visioの図形(Shape)は、単なる描画オブジェクトではない。内部的には複雑なセル群(Cells)のツリー構造を持つ COM オブジェクトであり、その生存期間中、識別特性の異なる3つのプロパティによって管理されている。

ShapeID(整数値 / Integer)

  • 定義: ページ(Page)またはマスターシェイプ(Master)内での一意な整数インデックス。
  • 特性: 図形が生成された順序やレイアウトの都合で動的に割り振られる。図形を削除・追加するとIDの再利用やズレが発生するため、「永続的な識別子」としては絶対に使ってはならない
  • 存在意義: 実行時における高速な配列アクセス、およびイテレーション(ループ処理)におけるパフォーマンスの要。

Name(文字列 / String)

  • 定義: ユーザーインターフェース(UI)上に表示されるローカライズされた図形名(例: “プロセス.12″)。
  • 特性: 言語環境(Locale ID)に強く依存する。 日本語版Visioであれば日本語、英語版であれば英語のプレフィックスに変化する。また、ユーザーがUI上で名前を変更すれば容易に書き換わる。
  • 存在意義: 人間がデバッグ時にイミディエイトウィンドウで視認するためのもの。コードのロジックに組み込むべきではない。

NameU(文字列 / String – Universal Name)

  • 定義: Visioの内部エンジンが使用する、言語非依存のグローバルな一意名(例: “Process.12″)。
  • 特性: マルチリンガル環境およびシステム間連携の絶対的正義。 UIの表示言語が何であれ、`NameU`の値は世界共通である。開発者は常にこのプロパティを基準に設計を行わなければならない。

2. 現場で頻発するアンチパターンと致命傷

多くの初学者、あるいは我流でVBAを書いてきたプログラマが陥る罠が、`Name`プロパティによるハードコーディングや、`ShapeID`の永続化への過信である。

‘ 【悪夢のようなアンチパターン】
‘ 1. Nameを使っているため、英語版Visioで実行した瞬間にRun-time error ‘-20000 (The requested name does not exist)’ が発生する。
‘ 2. 図形を一度削除して再配置するとIDが変わるため、ShapeIDのハードコーディングは数日で破綻する。
Dim targetShape As Visio.Shape
Set targetShape = ActivePage.Shapes.ItemU(“プロセス.1”) ‘ 文化的爆弾

この脆弱性を根絶するためには、「探索にはNameUを使い、処理のループ内ではShapeIDのインデックスアクセスによるO(1)の高速性を担保する」という二段構えのアーキテクチャが必要となる。

3. 実装コード:ロバストな図形取得とメモリ最適化の極意

以下のコードは、多言語環境やレガシー図面においても耐えうる、実務レベルの図形取得および操作のテンプレートである。

メモリリークを防ぐため、取得したShapeやPageオブジェクトはスコープを抜け次第、明示的に `Nothing` を代入してCOM参照カウンタを適切に解放している点に注目してほしい。

Option Explicit

Public Sub ProcessTargetShapeSafely()
Dim vsoPage As Visio.Page
Dim vsoShape As Visio.Shape
Dim targetShapeID As Long

‘ エラーハンドリングの要塞化
On Error GoTo ErrorHandler

‘ アクティブページの取得(COMオブジェクトの参照)
Set vsoPage = ActivePage
If vsoPage Is Nothing Then
MsgBox “アクティブなページが存在しません。”, vbCritical
Exit Sub
End If

‘ 【極意】NameU(ユニバーサル名)を用いて図形を特定し、そのShapeIDを抽出する
‘ これにより、言語依存のエラーを完全に回避する
targetShapeID = GetShapeIDByNameU(vsoPage, “ProcessNode_Alpha”)

If targetShapeID = -1 Then
MsgBox “対象の図形が見つかりません。NameUを確認してください。”, vbExclamation
GoTo Cleanup
End If

‘ ShapeIDが確定したため、O(1)の高速アクセスでオブジェクトを取得
Set vsoShape = vsoPage.Shapes.ItemFromID(targetShapeID)

‘ 図形に対するビジネスロジックの実行
ExecuteBusinessLogic vsoShape

Cleanup:
‘ —————————————————————–
‘ メモリ最適化:COMオブジェクトの明示的解放
‘ Visio VBAでは、参照の解放漏れがヒープ断片化やExcel/Visioプロセスの
‘ ゾンビ化(バックグラウンド残り)を引き起こす主原因となる。
‘ —————————————————————–
Set vsoShape = Nothing
Set vsoPage = Nothing
Exit Sub

ErrorHandler:
MsgBox “予期せぬエラーが発生しました: ” & Err.Description, vbCritical
Resume Cleanup
End Sub

‘ —————————————————————–
‘ 補助関数: NameUを走査して対応するShapeIDを返す(O(N)の探索)
‘ —————————————————————–
Private Function GetShapeIDByNameU(ByVal pageObj As Visio.Page, ByVal universalName As String) As Long
Dim shp As Visio.Shape
Dim foundID As Long

foundID = -1 ‘ 初期値(見つからない場合)

For Each shp in pageObj.Shapes
‘ NameUプロパティを大文字小文字を区別せずに比較(必要に応じてStrCompを使用)
If UCase(shp.NameU) = UCase(universalName) Then
foundID = shp.ID
Exit For
End If

‘ グループ化されている図形(子図形)の再帰的探索が必要な場合はここにロジックを追加する
‘ (今回は省略)
Next shp

GetShapeIDByNameU = foundID

‘ ループ変数としてのshpの解放
Set shp = Nothing
End Function

‘ —————————————————————–
‘ ビジネスロジックのサンプル
‘ —————————————————————–
Private Sub ExecuteBusinessLogic(ByRef shp As Visio.Shape)
‘ プロパティの書き換えや外部システム連携データのバインド
shp.CellsU(“LineColor”).FormulaU = “RGB(255, 0, 0)”
‘ ログ出力やAPI連携処理をここに記述
End Sub

4. チーフアーキテクトからの提言

システム間連携(例えば、データベースや外部REST APIから取得したメタデータをVisioの図形にマッピングする処理)において、IDやNameをコード内に直書きすることは「技術的負債の即時発注」に他ならない。

1. 設計時は必ず `NameU`(またはカスタムプロパティ/Shape Data)をキーにする。
2. 実行時は最初に `NameU` から `ShapeID` をルックアップ(逆引き)し、以降の重いループ内では `ShapeID` で高速アクセスする。
3. 使い終わったCOMオブジェクトは必ず `Set obj = Nothing` で解放し、Excel/Visioのプロセスリークを根絶する。

この鉄の掟を遵守するだけで、あなたの書くVisio VBAコードは、数千個の図形を持つ巨大な図面であっても、瞬時に、かつエラーフリーで稼働する堅牢なシステムへと生まれ変わる。妥協なきコードこそが、エンジニアの最大の武器である。

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