【入門編】Document.Mastersに存在しないマスターシェイプを外部ステンシル(.vssx)からサイレント自動ロードする補完ロジック – Visio VBA解析バイブル

スポンサーリンク

こんにちは!Visio VBAの世界へようこそ。

VisioのVBA(Visual Basic for Applications)は、ExcelやWordのVBAに比べて少し特殊なオブジェクトモデルを持っています。そのため、「マクロの記録」から一歩踏み出そうとした瞬間に、「思った通りに動かない!」「エラーで止まってしまう!」と頭を抱えてしまう方がとても多い世界でもあります。

でも、安心してください。今回のテーマをクリアすれば、Visio VBAの基本構造を完全にコントロールできるようになり、実務でガシガシ使える「絶対にエラーで落ちないプロ仕様のツール」が作れるようになりますよ。

今回は、実務で最も頻出するトラブル「描画したいマスターシェイプがドキュメント内に見つからないエラー」を、外部ステンシル(`.vssx`)からバックグラウンドで自動的にロードして解決する「サイレント自動ロード補完ロジック」を丁寧に解説します。

少し長めの記事ですが、図解を交えて1ステップずつ進めていきますので、温かいコーヒーでも飲みながら、一緒に学んでいきましょう!

1. Visioオブジェクトモデルの全体像を掴もう!

まずは、Visio VBAを操作する上での「基本のロードマップ」を整理しておきます。
ここを理解していると、この後のコードが驚くほどスムーズに読めるようになります。

Visioのオブジェクトは、以下のような階層構造(親子関係)になっています。

[Application (Visioアプリ全体)]

└─ [Documents (開いているすべての文書・ステンシル)]

└─ [ActiveDocument (現在操作中の図面)]
├─ [Pages (ページ全体の集まり)]
│ └─ [Page (具体的な1ページ)] ── [Shapes (描画されたシェイプ)]

└─ [Masters (この図面内に「登録」されている金型の一覧)]

重要なポイント:「マスター(Master)」と「シェイプ(Shape)」の違い

初学者の型が一番混乱しやすいのが、「マスターシェイプ」「シェイプ」の違いです。

  • マスター(Master):

図面の「金型(スタンプの本体)」です。図面の中に定義として存在しますが、目に見える形ではページに配置されていません。

  • シェイプ(Shape):

金型(マスター)をページにポンと押して作成された「実体(スタンプの跡)」です。私たちが普段、画面上で移動させたり文字を書いたりしているのは、すべてこの「シェイプ」です。

Visioでプログラムから図形を描くとき、基本的には「このマスターを使って、ページ上のX座標・Y座標にシェイプを配置(Drop)しなさい」という命令を記述します。

2. なぜ「マスターが見つからない」エラーが起きるのか?

一番シンプルな描画コード(マクロ記録を少し整理したもの)は、大体以下のようになります。

‘ ※これはエラーが起きやすい「発展途上」のコードです
Sub DrawProcessShape()
Dim vsoPage As Visio.Page
Set vsoPage = ActivePage

‘ アクティブドキュメントの「Masters」から「プロセス」という金型を探して配置
vsoPage.Drop ActiveDocument.Masters(“プロセス”), 4.5, 5.5
End Sub

このコードは、すでに図面内に「プロセス」というシェイプが1回以上手動で配置されている場合は、正常に動きます。

しかし、「新規作成したばかりのまっさらな図面」で実行すると、100%エラー(「アイテムは無効なコンテナ内にあるか、存在しません」等)になります。

なぜなら、新規図面の `ActiveDocument.Masters` コレクションの中には、まだ「プロセス」という金型が登録されていないからです。

解決へのアプローチ:無ければ外部から「こっそり」持ってくる

エラーを回避するためには、以下のスマートな補完ロジックが必要になります。

1. 図面の中に、目的のマスター(例:「プロセス」)が既にあるか探す。
2. 【あれば】 それを使ってそのまま描画する。
3. 【なければ】

  • 目的のマスターが保管されている外部ステンシル(`.vssx`ファイル)を、ユーザーに気づかれないように「非表示(サイレント)」で開く。
  • そこから目的のマスターをコピーして図面にロードする。
  • 開いた外部ステンシルを、そっと閉じる。

4. ロードしたマスターを使って、安全に描画する。

この「大人の気配り」ができるコードこそが、実務で喜ばれるプロのプログラムです。

3. 【プロの極意】ステンシルを「サイレント」で開く魔法の引数

Visioで外部ファイルを開くとき、普通に `Documents.Open` を使うと、画面の左側にステンシルウィンドウが「ポンッ」と表示されてしまいます。これではユーザーが驚いてしまいますし、画面のチラつき(描画負荷)の原因にもなります。

これを防ぐために、プロは `Documents.OpenEx` メソッドを使用します。

‘ 外部ステンシルを「読み取り専用」かつ「非表示」で開く
Set vsoStencilDoc = Documents.OpenEx(“ファイルのフルパス”, visOpenRO + visOpenHidden)

  • `visOpenRO` (値: 2) :

読み取り専用(Read Only)で開きます。元のステンシルファイルを誤って書き換えるリスクを防ぎます。

  • `visOpenHidden` (値: 64) :

非表示(Hidden)で開きます。これが「サイレント自動ロード」の心臓部となる、最も重要なフラグです。

4. 実用性100%!サイレント補完ロード付きの描画コード

それでは、ここまでの知識を凝縮した、実務にそのまま使えるVBAコードをご紹介します。

このコードは、標準の「基本フローチャート」ステンシル(`BASFLO_M.VSSX`)から「プロセス」マスターをサイレントでインポートし、安全に描画する一連の流れを完全に網羅しています。

Option Explicit

”’

”’ 存在しないマスターを外部ステンシルから自動ロードして描画するメインルーチン
”’

Sub SafeDropShapeSample()
Dim targetPage As Visio.Page
Set targetPage = ActivePage

‘ 1. 配置したいマスターの名前を定義
Dim masterName As String
masterName = “プロセス” ‘ ※お使いの環境に合わせて変更してください(例: “Process”)

‘ 2. マスターを安全に取得(無ければ自動ロード)
Dim targetMaster As Visio.Master
Set targetMaster = GetOrLoadMaster(masterName)

‘ 3. 取得できた場合のみ、安全に配置する
If Not targetMaster Is Nothing Then
Dim droppedShape As Visio.Shape
‘ ページの中心付近(横4.5インチ、縦5.5インチ)に配置
Set droppedShape = targetPage.Drop(targetMaster, 4.5, 5.5)

‘ 配置したシェイプにテキストを書き込んでみる
droppedShape.Text = “自動ロード成功!”
MsgBox “安全にシェイプを配置しました!”, vbInformation, “成功”
Else
MsgBox “マスター ‘” & masterName & “‘ をロードできませんでした。”, vbCritical, “エラー”
End If
End Sub

”’

”’ アクティブドキュメントからマスターを探し、無ければ外部ステンシルから自動ロードする関数
”’

”’ 取得したいマスターの正確な名前 ”’ 取得したMasterオブジェクト(見つからない場合はNothing)
Private Function GetOrLoadMaster(ByVal masterName As String) As Visio.Master
Dim activeDoc As Visio.Document
Set activeDoc = ActiveDocument

‘ — ステップ1: アクティブ図面内に既に存在するかチェック —
On Error Resume Next
Dim foundMaster As Visio.Master
Set foundMaster = activeDoc.Masters.ItemU(masterName) ‘ ItemUはシステム内部名での安全な指定
On Error GoTo 0

‘ 既にある場合は、それをお返しして終了
If Not foundMaster Is Nothing Then
Set GetOrLoadMaster = foundMaster
Exit Function
End If

‘ — ステップ2: 存在しない場合、外部ステンシルからロードする —
‘ ※ここでは、Visio標準の「基本フローチャート (US単位/メトリック両対応)」ステンシルをターゲットにします
Dim stencilPath As String
‘ Visioがインストールされているシステムパスから標準ステンシルを特定
stencilPath = Application.MyShapesPath & “\..\..\..\..\1041\BASFLO_M.VSSX”

‘ 環境によってパスが変わるため、見つからない場合は代表的なファイル名で代用
‘ (実務では、社内共有サーバーの絶対パスや、マクロブックと同じフォルダなどを指定するのがお勧めです)
If Dir(stencilPath) = “” Then
‘ パスが見つからない場合のフォールバック(例:ローカルの一時フォルダなど)
stencilPath = “C:\Program Files\Microsoft Office\root\Office16\Visio Content\1041\BASFLO_M.VSSX”
End If

‘ ファイルの存在最終確認
If Dir(stencilPath) = “” Then
MsgBox “外部ステンシルファイルが見つかりません:” & vbCrLf & stencilPath, vbExclamation, “ロード不可”
Set GetOrLoadMaster = Nothing
Exit Function
End If

‘ — ステップ3: 外部ステンシルを「サイレント」で開く —
Dim stencilDoc As Visio.Document
On Error Resume Next
‘ visOpenRO (読み取り専用) + visOpenHidden (画面非表示)
Set stencilDoc = Application.Documents.OpenEx(stencilPath, visOpenRO + visOpenHidden)
On Error GoTo 0

If stencilDoc Is Nothing Then
MsgBox “ステンシルを開けませんでした。”, vbCritical
Set GetOrLoadMaster = Nothing
Exit Function
End If

‘ — ステップ4: 外部ステンシルからマスターをインポート —
Dim sourceMaster As Visio.Master
On Error Resume Next
Set sourceMaster = stencilDoc.Masters.ItemU(masterName)
On Error GoTo 0

If Not sourceMaster Is Nothing Then
‘ ActiveDocumentのMastersコレクションに、外部のマスターを追加(インポート)
‘ ※Visioでは、Dropメソッドに外部マスターを直接渡すだけでも自動インポートされますが、
‘ このように明示的に図面側にDrop(登録)しておくと、コードの意図が明確になり堅牢です。
Set foundMaster = activeDoc.Masters.Drop(sourceMaster, 0, 0)
End If

‘ — ステップ5: 後片付け(開いたステンシルを閉じる) —
‘ これを忘れると、バックグラウンドでファイルがロックされたままになり、次回実行時にエラーになります
stencilDoc.Close

‘ 最終結果を返す
Set GetOrLoadMaster = foundMaster
End Function

5. 初学者が陥りやすい「3つの罠」とプロの対策

このコードを実装するにあたり、多くの人が躓く(つまづく)ポイントを先回りして解説しておきますね。

① 外部ステンシルが開きっぱなしになる罠(メモリリーク)

コードの途中でエラーが発生してプログラムが強制終了すると、`stencilDoc.Close` に到達せず、「画面には見えないけれど、裏でステンシルファイルが開いたまま」という状態になります。
この状態で再度プログラムを動かすと、「ファイルが既に使用されています」という予期せぬエラーに繋がります。

  • 対策:

エラーが発生しても必ず `Close` 処理を通るように、実際の業務コードでは `On Error GoTo ErrorHandler` などのエラーハンドリングを構築し、`ErrorHandler:` の手前や中で確実に `stencilDoc.Close` が実行されるように設計します。

② ステンシルの「ファイルパス」が変わる罠

上記のコードでは、Officeの標準インストールパスを推測して指定していますが、Officeのバージョン(32bit/64bit)や言語パック(1041は日本語、1033は英語)によって、ファイルの保存場所は微妙に異なります。

  • 対策:

自社専用のカスタムステンシルを使用する場合は、マクロを実行する図面と同じフォルダにステンシルを配置し、`ActiveDocument.Path & “MyStencil.vssx”` のように相対パスで指定するのが最も安全で、運用の手間がかかりません。

③ 「日本語名(ローカル名)」と「英語名(ユニバーサル名)」の罠

Visioは多言語対応のため、シェイプに「プロセス(日本語表示名)」と「Process(システム内部名)」の2つの名前を持っています。
コードの中で `Masters.Item(“プロセス”)` と書くと、英語環境のVisioで動かした時にエラーになります。

  • 対策:

コード内で使用している `Masters.ItemU` の `U` は「Universal(ユニバーサル)」の頭文字です。可能な限り、内部で一意に決まっているユニバーサル名(例: `”Process”`)を使用する癖をつけておくと、将来的に海外拠点と図面を共有した際にもビクともしないグローバル仕様のプログラムになります。

6. まとめ:ここをクリアすれば、Visio VBAの基本はバッチリ!

お疲れ様でした!
今回学んだ内容を振り返ってみましょう。

1. マスター(スタンプの本体)がないと、ページにシェイプ(スタンプの跡)は押せない。
2. 図面内にマスターがなければ、外部から持ってくる必要がある。
3. 外部から持ってくるときは、`Documents.OpenEx` で `visOpenHidden` を指定して「静かに美しく」処理する。
4. 開いた外部ステンシルは、裏でロックされないように必ず閉じる

この「存在チェック ➔ なければ裏で開いてロード ➔ 後片付け」という一連の流れは、Visio VBAにおける「最も美しく、最も堅牢な王道パターン」です。

これが理解できれば、Visio VBAの基礎はもうバッチリ合格点ですよ!マクロ記録のコードとは一線を画す、実用的でスマートなツールが作れるようになっているはずです。

もし、会社の業務で「この処理を自動化したいな」と思うものがあれば、ぜひ今回のコードをベースに応用してみてくださいね。

あなたの自動化ライフが、より快適なものになることを応援しています!

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