こんにちは! Visioの自動化の世界へようこそ。
マクロの記録ボタンを押して、生成された呪文のようなコードをそのまま動かしてみたものの、「あれ? 別のPCで動かすとエラーになる…」「なぜか図形が見つからない…」と頭を抱えていませんか?
そう、Visio VBAの初学者が最初に直面する最大の壁、それが「外部のステンシルファイル(.vssx)依存問題」です。
「C:\Users\…\MyShapes.vssx」なんてパスをコードに直書きしているそこのあなた。そのツール、他のメンバーに配ったら一発で動かなくなりますよ。
今回は、プロの現場でも必須となる「外部ファイルに依存せず、ステンシルから必要なマスターシェイプを動的に取り込んで図形を生成する技術」を、優しく、そして本質的な部分まで徹底的に解説します。
ここをクリアすれば、あなたの作るVisioツールは「どこでも動く配付可能なプロ仕様」へと生まれ変わります。さあ、一緒に扉を開けましょう!
—
なぜ「外部ファイル依存」は悪なのか?
Visioで図形を描画するとき、私たちは通常、画面の左側にある「ステンシル」から図形をドラッグ&ドロップしますよね。VBAでこれを自動化しようとすると、つい次のようなコードを書きがちです。
‘ 【やってはいけないアンチパターン例】
Dim shp As Visio.Shape
‘ 外部のステンシルファイルを直接開こうとする
Dim stnDoc As Visio.Document
Set stnDoc = Documents.OpenEx(“C:\Work\MyCustomShapes.vssx”, visOpenDocked)
‘ マスターを取得して図形を配置
Set shp = ActivePage.Drop(stnDoc.Masters(“サーバー”), 2, 2)
このコードの何がいけないのでしょうか?
1. パスの固定化: ファイルサーバーの構成が変わったり、担当者のPCのローカル環境が変わったりした瞬間、パスが見つからずエラー(実行時エラー)になります。
2. ファイルの散逸: ツール本体(.vsmや.vsdm)のほかに、依存するステンシル(.vssx)もセットで配る必要があり、バージョン管理が破綻します。
解決策:マスターをドキュメントの「内臓」にしてしまおう!
Visioのドキュメント(`Document`オブジェクト)は、実は自分自身の中にマスターシェイプを保持する領域(`Masters`コレクション)を持っています。
つまり、「ツール起動時に、隠しフォルダーやリソースから一時的にステンシルを開き、必要なマスターだけを現在のドキュメント内にコピー(ドロップ)して、ステンシル自体は即座に閉じる」というアプローチを取れば、最終的にできあがるVisioファイルは「単一ファイルで完全に完結(スタンドアロン)」するのです。
これが、今回マスターする「動的ロード」の神髄です。
—
Visioオブジェクトモデルの基本関係
コードを書く前に、Visioの階層構造(オブジェクトモデル)を頭に焼き付けておきましょう。
Application (Visio全体)
┗ Documents (開かれているファイル群)
┗ ActiveDocument (現在のドキュメント)
┣ Pages (ページ群)
┃ ┗ ActivePage (操作中のページ)
┗ Masters (このドキュメントが持つマスターシェイプ群) ← ★ここが重要!
マスターシェイプは、ページに配置されると「Shape」になり、ドキュメントにインポートされると「Master」として `ActiveDocument.Masters` に宿ります。
—
実践!マスターシェイプ動的ロードの完全コード
それでは、現場でそのまま使える実用的なVBAコードを公開します。
このコードは、同じフォルダ内(または特定のパス)にあるステンシルから、指定したマスターを自ドキュメントに取り込み、ページ上に図形を生成するサンプルです。
Sub CreateShapeWithoutExternalDependency()
‘ — 変数の宣言 —
Dim targetStencilPath As String
Dim stnDoc As Visio.Document
Dim targetMaster As Visio.Master
Dim generatedShape As Visio.Shape
Dim masterName As String
‘ 取得したいマスターシェイプの名前(ステンシル内の名前)
masterName = “クラウドサーバー”
‘ 1. ステンシルファイルのパスを決定する
‘ ※ここではこのVBAファイル(ActiveWorkbook等に相当するもの)と同じ階層を想定
‘ Visioの場合は ThisDocument.Path を使うと、現在の図面と同じフォルダを取得できます。
targetStencilPath = Visio.ActiveDocument.Path & “Infrastructure.vssx”
‘ ファイルが存在するか簡易チェック
If Dir(targetStencilPath) = “” Then
MsgBox “必要なステンシルが見つかりません: ” & vbCrLf & targetStencilPath, vbCritical, “エラー”
Exit Sub
End If
On Error GoTo ErrorHandler
‘ 2. ステンシルファイルを「非表示(ドッキングなし)」で開く
‘ visOpenHidden を使うことで、ユーザーに余計なウィンドウを見せずに裏で開けます。
Set stnDoc = Visio.Documents.OpenEx(targetStencilPath, visOpenHidden)
‘ 3. 開いたステンシルから目的のマスターが存在するか確認しつつ取得
On Error Resume Next
Set targetMaster = stnDoc.Masters(masterName)
On Error GoTo ErrorHandler ‘ エラートラップを戻す
If targetMaster Is Nothing Then
MsgBox “指定されたマスターシェイプが見つかりません: ” & masterName, vbExclamation, “確認”
stnDoc.Close
Exit Sub
End If
‘ 4. 【核心】自ドキュメントの Masters コレクションにマスターが存在するかチェックし、なければコピー
‘ (Visio.Document.Dropを実行すると自動的に取り込まれますが、明示的に存在確認するロジックです)
Dim localMaster As Visio.Master
On Error Resume Next
Set localMaster = ActiveDocument.Masters(masterName)
On Error GoTo ErrorHandler
If localMaster Is Nothing Then
‘ ドキュメントにまだこのマスターがない場合、ステンシルからマスターをドキュメントへコピー
‘ (DropExやMasterオブジェクトの複製を利用する方法もありますが、
‘ 最も手軽で確実なのは、一度ダミーのドロップを行うか、ドキュメントのMasters.AddUを使う方法です)
‘ 今回は一番スマートな Masters.AddU を使ったマスターの取り込み手法を採用します
Set localMaster = ActiveDocument.Masters.AddU(targetMaster)
End If
‘ 5. 使い終わった外部ステンシルファイルは速やかに閉じる(メモリ解放の鉄則!)
stnDoc.Close
‘ 6. 自ドキュメント内に取り込んだ(または既存の)マスターを使って、アクティブページに図形を配置!
‘ 座標 (4.0, 5.0) の位置にドロップします(単位はインチ)
Set generatedShape = ActivePage.Drop(localMaster, 4.0, 5.0)
‘ 7. 仕上げ:生成した図形に対して初期設定を行う
generatedShape.Text = “Webサーバー 01”
MsgBox “図形の動的生成に成功しました!”, vbInformation, “完了”
Exit Sub
ErrorHandler:
‘ 予期せぬエラー時のクリーンアップ
MsgBox “エラーが発生しました: ” & Err.Description, vbCritical, “予期せぬエラー”
If Not stnDoc Is Nothing Then
‘ エラー時でもステンシルが開いていれば確実に閉じる
stnDoc.Close
End If
End Sub
—
コードの重要ポイントとエンジニアの知見
上記のコードには、Visio VBAで飯を食っていくためのノウハウが凝縮されています。特に重要な3つのポイントを解説します。
① `visOpenHidden` で裏側でこっそり開く
`Visio.Documents.OpenEx` メソッドの第二引数に `visOpenHidden` を指定すると、ユーザーの画面にステンシルウィンドウを表示させることなく、メモリ上だけでファイルを開くことができます。
画面がガチャガチャと切り替わらない、洗練されたツールを作るための必須テクニックです。
② メモリリークを防ぐ「必ず閉じる」執念
VBAにおいて、外部ファイルを `Open`(または `OpenEx`)したら、処理の成否に関わらず絶対に `Close` するのがプロの作法です。
今回のコードでは `On Error GoTo ErrorHandler` を用意し、万が一途中でエラーが起きた場合でも、必ず `stnDoc.Close` が実行されるように保険をかけています。これを怠ると、Visioのプロセスがタスクマネージャーに残る「ゾンビプロセス問題」を引き起こします。
③ `ActiveDocument.Masters.AddU` による完全カプセル化
外部ステンシルから `targetMaster` を取得した後、`ActiveDocument.Masters.AddU(targetMaster)` を使うことで、そのマスターの遺伝子(図形の形状、マスタープロパティ、シェイプシートの数式など)のすべてが、あなたの描いているVisioファイルの中に完全にコピーされます。
これにより、後から外部の `.vssx` ファイルを削除しようが、別のPCにファイルをメールで送ろうが、図形はエラーなく完璧に描き続けられます。
—
まとめ:あなたのVisioマクロを「配布できる資産」へ
今回は、`Document.Masters` とステンシルファイルを連携させ、外部依存のない動的な図形生成を行う方法を解説しました。
- 外部の `.vssx` はそのまま配らない。
- 必要なマスターは、実行時に自ドキュメントの `Masters` にインポートする。
- 開きっぱなしにせず、エラーハンドリングを含めて確実にクローズする。
この3つを守るだけで、あなたが作るVisioマクロの品質はプロレベルへと一気に跳ね上がります。
現場で「おっ、このツール使いやすいしエラーも出ないな」と言われるエンジニアを目指して、ぜひご自身の環境でも試してみてください。
それでは、快適なVisio自動化ライフを!
