Visio VBAの深淵:`Shape.ObjectType`で制御する、堅牢な図形判定のアーキテクチャ
VisioのVBA開発において、初心者が最初に突き当たる壁は「動いたはずのコードが、特定の図形で突然エラーを吐いて止まる」という現象だ。
なぜか?
答えはシンプルだ。「VisioのShapeは、見た目は同じ図形でも、内部的な出自(メタデータ)が全く異なるから」だ。
グループ図形に対して`ForeignObject`特有のプロパティを叩けばエラーになり、ガイド線に対して通常のシェイプ操作を行えば予期せぬ挙動を招く。これを「なんとなく」のコーディングで回避しようとするのは、爆弾を抱えてコードを書いているのと同じである。
本稿では、`Shape.ObjectType`を軸とした、堅牢でプロフェッショナルな図形判定の作法を伝授する。
—
1. なぜ「厳密な判定」が必要なのか
Visioの`Shape`オブジェクトは、いわば「多形的な怪物」だ。`visTypeGroup`(グループ)、`visTypeForeignObject`(ビットマップやCADデータ)、`visTypeGuide`(ガイド線)など、内部構造が根本から異なるものがすべて`Shape`という一つの型に押し込められている。
業務自動化ツールを組む際、これらを無差別にループ処理すると、以下の悲劇が待っている。
- Runtime Error 13(型不一致): 特定のオブジェクトにしか存在しないプロパティを呼び出した瞬間に発生。
- 例外の連鎖: グループ図形の中にさらに図形が混在している場合、再帰処理での設計ミスによりスタックオーバーフローや予期せぬ参照エラーを誘発。
これらを防ぐ唯一の手段が、「処理の入り口で、オブジェクトの素性を正確に識別する」ことだ。
—
2. 実践:安全な図形分岐のパターン
以下に、実務レベルで必ず導入すべき「判定の定石」を示す。この構造をベースにすれば、どんな複雑な図形構造でも安全に制御可能だ。
‘ @description シェイプの種類に応じて安全に処理を分岐するプロフェッショナルなテンプレート
Public Sub ProcessShapes(ByVal shp As Visio.Shape)
‘ 1. まずはObjectTypeで厳密に判別
Select Case shp.ObjectType
Case Visio.VisObjectType.visTypeShape
‘ 通常のシェイプ(マスターから生成されたもの等)
‘ ここで初めて具体的な処理を行う
Call ProcessNormalShape(shp)
Case Visio.VisObjectType.visTypeGroup
‘ グループ化されたシェイプ
‘ 再帰処理が必要なケースが多い
Debug.Print “Group Found: ” & shp.Name
Case Visio.VisObjectType.visTypeForeignObject
‘ OLEオブジェクトや画像、CADデータ
‘ これらはForeignプロパティで制御する
Debug.Print “Foreign Object Detected: ” & shp.Name
Case Visio.VisObjectType.visTypeGuide
‘ ガイド線(無視すべきケースがほとんど)
Exit Sub
Case Else
‘ その他(Unknown)はログに逃がす
Debug.Print “Unsupported type: ” & shp.ObjectType
End Select
End Sub
—
3. アーキテクトの知見:設計上の注意点
このコードをプロダクション環境に実装する際、以下の3つの観点を忘れてはならない。
① 再帰処理(Recursive Loop)の罠
グループ図形を処理する場合、`shp.Shapes`をループさせる再帰関数を書くことになるだろう。その際、「最大階層数」を考慮すること。無限ループを防ぐため、必ず現在の階層をカウントする引数を持たせるのが、経験あるエンジニアの流儀だ。
② データベース/外部連携時のメタデータ
Visio図形からデータを吸い上げてDBへ格納するツールを作る場合、`ObjectType`だけで判断せず、必ず`Shape.Name`や`Shape.ID`と共に`Shape.Type`(ShapeSheet上の属性)を組み合わせよ。特に「カスタムプロパティ(Shape Data)」の有無を判定条件に加えることで、業務データと単なる図形を明確に分離できる。
③ パフォーマンスの最適化
`Shape`をループする際、`ScreenUpdating`を一時的に停止させるのは基本中の基本だが、それ以上に「不要なオブジェクトを判定の初期段階で弾く(Early Return)」ことを徹底せよ。`If shp.Type = visTypeGuide Then GoTo Next_Shape` といったガード節を置くだけで、数千個の図形を扱う際の実行速度は劇的に変わる。
—
結びに:コードは「防御」から始まる
Visio VBAは、オブジェクトモデルの理解度によって、その安定性が天と地ほど変わる。
今回紹介した`ObjectType`による分岐は、決して「面倒な儀式」ではない。あなたが書いたツールを、誰が使ってもクラッシュしない「業務のインフラ」へと昇華させるための、最低限の防衛ラインだ。
コードを書き始める前に、まずはそのシェイプが何者であるかを問いかけよ。その一呼吸が、無用なバグ報告から君を解放してくれるはずだ。
さあ、次は君自身のコードでこのロジックを実装してみてほしい。その瞬間に、Visioは「お絵かきソフト」から「データ駆動型の自動化エンジン」へと変貌を遂げる。
