【テクニカル・上級編】【実務直結】ページ名に日付を含める自動命名規則と、古いページをアーカイブ用レイヤーへ自動移動する運用フロー – Visio VBA解析バイブル

スポンサーリンク

Visio VBAを掌握する極限の知見:図面履歴の完全自動化とアーカイブ・エンジニアリング

Microsoft Visioは、エンタープライズアーキテクチャの設計図からネットワークトポロジ、プラントの配管図に至るまで、ミッションクリティカルなビジュアルデータが集積する場である。しかし、多くの現場で「バージョンの乱立」「過去の変更履歴のロスト」「手動による無秩序なページ複製」という原始的な課題が放置されている。

「古いページを消すな、しかし視界から排除せよ。そして全ての命名はシステムが統御しろ」

本稿では、Visio VBAの内部構造(COMコンポーネントのライフサイクル、非効率なDOM走査の排除、レイヤー制御の極意)を熟知したシニアエンジニアに向け、「ページ名への日付自動付与による命名規則の強制」と、「古いページを削除せずにアーカイブ専用レイヤー(概念的・物理的退避)へ押しやる運用フロー」を実装する、実務直結の極限コードを提示する。

—

1. Visio VBAにおけるオブジェクトライフサイクルとパフォーマンスの現実

多くの初学者は、`ActivePage` や `ActiveDocument` を安易に乱用し、COMのマーシャリングオーバーヘッドや暗黙のインスタンス生成によるメモリリークの罠に落ちる。VisioのDOMは、オブジェクトの参照を適切に解放(`Set obj = Nothing`)しないと、VBE(Visual Basic Editor)のプロセス内にゴミが残り、最悪の場合、Visioそのものがクラッシュする。

特にページやシェイプを大量に操作するバッチ処理では、以下の鉄則を遵守せよ。

  • 画面描画の完全な抑制(`ScreenUpdating`): DOM操作のたびにUIスレッドが再描画を走らせると、処理速度が数百倍に低下する。
  • イベントの無効化(`EventEnabled`): 不要なイベントハンドラの誘発を防ぐ。
  • オブジェクト変数の厳密なスコープ管理と解放: 処理のループ内での暗黙の参照保持を断ち切る。

—

2. 実装アーキテクチャ:自動命名とアーカイブ・フロー

今回構築するシステムの中核は以下の2点である。

1. 命名規則の自動化: 新規ページ生成時、あるいは既存ページの確定時に `[YYYYMMDD]_[OriginalName]` のフォーマットを強制適用する。
2. アーカイブ・レイヤーへの退避: 過去バージョンのページに対し、専用の「Archive」レイヤーを動的にアサインし、非表示(ロック)状態にして図面ファイル内に凍結保存する。

冗長性を排除したプロダクション・コード

以下のモジュールをVisioのVBAプロジェクト(ThisDocument または 標準モジュール)に実装せよ。エラーハンドリングとメモリ解放のイディオムが完璧に組み込まれている。

Option Explicit

‘ ==============================================================================
‘ 業務自動化アーキテクチャ: ページ自動命名 & アーカイブ退避エンジン
‘ ターゲット: Visio 2013 / 2016 / 2019 / 2021 / Microsoft 365
‘ ==============================================================================

Public Sub ExecutePageArchivingFlow()
Dim vsoApp As Visio.Application
Dim vsoDoc As Visio.Document
Dim vsoPage As Visio.Page
Dim targetPageName As String
Dim todayStr As String

‘ 実行時のパフォーマンスを極限まで高めるための設定
Set vsoApp = Visio.Application
vsoApp.ScreenUpdating = False
vsoApp.EventEnabled = False
vsoApp.Settings.ShowChanges = False

On Error GoTo ErrorHandler

Set vsoDoc = vsoApp.ActiveDocument
If vsoDoc Is Nothing Then
MsgBox “アクティブなドキュメントが存在しません。”, vbCritical, “致命的エラー”
GoTo Finally
End If

‘ 1. 現在のアクティブページを取得し、日付プレフィックスを付与してリネーム
Set vsoPage = vsoApp.ActivePage
todayStr = Format(Date, “yyyymmdd”)

‘ 既に日付プレフィックスが付与されているか検証し、重複付与を防ぐ
If Not vsoPage.Name Like “

[0-9]_[0-9]” Then

targetPageName = todayStr & “_” & vsoPage.Name
vsoPage.Name = GetUniquePageName(vsoDoc, targetPageName)
End If

‘ 2. アーカイブ用レイヤーの取得または生成、およびシェイプの退避処理
Call ProcessPageToArchiveLayer(vsoPage)

‘ 3. 新規の作業用ページをクリーンな状態で生成
Dim vsoNewPage As Visio.Page
Set vsoNewPage = vsoDoc.Pages.Add()
vsoNewPage.Name = “Work_” & Format(DateAdd(“d”, 1, Date), “yyyymmdd”)

MsgBox “ページのアーカイブ化と新規ワークページの作成が完了しました。”, vbInformation, “自動化完了”

Finally:
‘ 確実なオブジェクト解放と環境復元
Set vsoNewPage = Nothing
Set vsoPage = Nothing
Set vsoDoc = Nothing
If Not vsoApp Is Nothing Then
vsoApp.ScreenUpdating = True
vsoApp.EventEnabled = True
vsoApp.Settings.ShowChanges = True
End If
Set vsoApp = Nothing
Exit Sub

ErrorHandler:
MsgBox “予期せぬエラーが発生しました: [” & Err.Number & “] ” & Err.Description, vbCritical, “システムエラー”
Resume Finally
End Sub

‘ ——————————————————————————
‘ ページ名の重複を防ぐためのサニタイズ関数
‘ ——————————————————————————
Private Function GetUniquePageName(ByRef vsoDoc As Visio.Document, ByVal baseName As String) As String
Dim candidateName As String
Dim i As Long
Dim isUnique As Boolean
Dim p As Visio.Page

candidateName = baseName
i = 1

Do
isUnique = True
For Each p In vsoDoc.Pages
If p.Name = candidateName Then
candidateName = baseName & “_” & i
i = i + 1
isUnique = False
Exit For
End If
5 Next p
Loop Until isUnique

GetUniquePageName = candidateName
Set p = Nothing
End Function

‘ ——————————————————————————
‘ ページ内の全シェイプを「Archive_Layer」に強制割当し、ロックする処理
‘ ——————————————————————————
Private Sub ProcessPageToArchiveLayer(ByRef vsoPage As Visio.Page)
Const LAYER_NAME As String = “ARCHIVED_LAYER”
Dim vsoLayers As Visio.Layers
Dim vsoLayer As Visio.Layer
Dim layerExists As Boolean
Dim shp As Visio.Shape

Set vsoLayers = vsoPage.Layers
layerExists = False

‘ 既存レイヤーの探索
For Each vsoLayer In vsoLayers
If vsoLayer.Name = LAYER_NAME Then
layerExists = True
Exit For
End If
Next vsoLayer

‘ 存在しない場合は新規作成
If Not layerExists Then
Set vsoLayer = vsoLayers.Add(LAYER_NAME)
End If

‘ レイヤーの属性設定(非表示・ロック・印刷不可へ設定)
vsoLayer.CellsC(VisLayerCells.visLayerColor).FormulaU = “RGB(180,180,180)”
vsoLayer.CellsC(VisLayerCells.visLayerLock).FormulaU = “TRUE”
‘ 必要に応じて非表示にする場合: vsoLayer.CellsC(VisLayerCells.visLayerVisible).FormulaU = “FALSE”

‘ ページ上のすべてのシェイプをアーカイブレイヤーに追加
For Each shp In vsoPage.Shapes
‘ 既にレイヤーに割り当てられていても追加メソッドで安全に包含可能
vsoLayer.Add shp, visLayerMember
Next shp

Set shp = Nothing
Set vsoLayer = Nothing
Set vsoLayers = Nothing
End Sub

—

3. チーフアーキテクトが解説するコードの急所

1. 例外処理における「リソースリークの絶対阻止」

VBAにはJavaやC#のような `try-finally` 構文がない。そのため、`On Error GoTo ErrorHandler` を用いたジャンプ処理を行う際、エラー発生時にも確実にオブジェクトの解放(`Set xxx = Nothing`)とアプリケーション設定の復元(`ScreenUpdating = True` など)を行わなければならない。これを怠ると、Visioがバックグラウンドプロセスとしてメモリ上に残留し続け、PCのメモリを食いつぶすゾンビプロセスと化す。上記のコードでは `Finally:` ラベルを設け、いかなる例外パスを通ろうとも必ずクリーンアップが走る堅牢な構造にしている。

2. 重複命名を防ぐサニタイズロジック

Visioでは、同一ドキュメント内に同一名のページが存在するとCOMエラー(`-2032488344` 等)が発生する。`GetUniquePageName` 関数は、既に存在するページ名を走査し、万が一同名のプレフィックスが存在する場合は自動的にインクリメント(`_1`, `_2`…)を付与することで、バッチ処理中の停止を完全に回避する。

3. レイヤーを活用した「物理削除しない」バージョン管理

安易なページの削除(`vsoPage.Delete`)は、過去の監査証跡やデザインの意思決定プロセスを闇に葬ることと同義である。本コードでは、ページを削除せず、全てのシェイプを `ARCHIVED_LAYER` に強制的に回収し、`visLayerLock` セルを `TRUE` に書き換えることで、「閲覧は可能だが、誤って編集できない凍結状態(ReadOnly Layer)」へと昇華させている。これにより、ファイル容量の肥大化を最小限に抑えつつ、単一ファイル内での完璧なタイムライン管理が成立する。

—

4. エンタープライズ運用への展開:外部システム連携の視野

このVBAマクロを単なるローカルツールで終わらせてはならない。
社内のGitやSharePoint、あるいはPLM(製品ライフサイクル管理)システム、保守管理DBと連携させるためには、このVBAの実行トリガーをWindowsタスクスケジューラや外部のPowerShellスクリプトからCOM経由で呼び出す形に拡張するのが定石である。

PowerShellからVisioマクロをサイレント実行し、自動アーカイブをキックするスニペット例
$visio = New-Object -ComObject Visio.Application
$visio.Visible = $false
$doc = $visio.Documents.Open(“C:\Enterprise\NetworkTopology.vsdm”)

マクロの実行
$visio.Run(“ThisDocument.ExecutePageArchivingFlow”)

$doc.Save()
$doc.Close()
$visio.Quit()
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($visio) | Out-Null

レガシーなツールと侮られがちなVisioであっても、アーキテクチャの原則を理解し、メモリとDOMのライフサイクルを完全に制御下に置けば、堅牢なエンタープライズ・エンジニアリングのピースとして完全に機能させることができる。

コードを信じよ、構造を統御せよ。あなたの図面管理フローは、今日から一変する。

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