Visio VSDX「肥大化」の深淵を断つ — 未使用マスター・スタイル徹底排除による軽量化の実装
大規模なVisio図面を扱っていると、必ず直面する「肥大化」という呪いがある。
コピー&ペーストを繰り返した図面は、ゴミのようなMaster(マスターシェイプ)やStyle(スタイル)を蓄積し、ファイルサイズは数MBから数十MBへ、そしてメモリを食いつぶす爆弾へと変貌する。
本稿では、表面的なマクロではなく、Visioのオブジェクトモデルの深層に踏み込み、「未使用定義の完全抹殺」を行うアーキテクトのための最適化手法を伝授する。
—
1. 肥大化の正体:ゴミが溜まるメカニズム
Visioの`.vsdx`ファイルは実質的にXMLの集合体である。不要なMasterやStyleが残存していると、解析コストが跳ね上がる。特に厄介なのは、図面からシェイプを削除しても、その定義(Master)や書式設定(Style)がDocumentのコレクション内に残存し続ける点だ。
これを放置することは、技術的負債を抱えながら運用するに等しい。我々エンジニアに必要なのは、「使用しているか否か」を再帰的に判定するアルゴリズムである。
—
2. 最適化アルゴリズムの核心
未使用定義を削除する手順は以下の通りだ。
1. 全ページの全シェイプを走査し、使用されている`Master`のIDをHashSet(または辞書)に格納する。
2. `Document.Masters`をループし、上記辞書に存在しないものを削除する。
3. 同様に、`Styles`についても使用状態を判定してクリーンアップを行う。
実装コード:Master Cleanup Engine
Option Explicit
‘ 大規模ファイルを扱うため、オブジェクト参照の管理を徹底する
Public Sub OptimizeVisioDocument()
Dim doc As Visio.Document
Set doc = ActiveDocument
Dim usedMasters As Object
Set usedMasters = CreateObject(“Scripting.Dictionary”)
‘ 1. 使用中のマスターを特定(再帰的に探索)
Dim pg As Visio.Page
For Each pg In doc.Pages
Call ScanShapesForMasters(pg.Shapes, usedMasters)
Next
‘ 2. 未使用マスターの削除
Dim i As Long
‘ コレクション削除は逆順で行うのが定石
For i = doc.Masters.Count To 1 Step -1
Dim mst As Visio.Master
Set mst = doc.Masters(i)
‘ 組み込みステンシル等は削除対象外にするガードが必要
If Not usedMasters.Exists(mst.Name) And Not mst.Hidden Then
mst.Delete
Debug.Print “Deleted Master: ” & mst.Name
End If
Next i
‘ メモリ解放
Set usedMasters = Nothing
MsgBox “最適化完了: 不要なマスターを抹殺しました。”, vbInformation
End Sub
Private Sub ScanShapesForMasters(shapes As Visio.Shapes, dict As Object)
Dim shp As Visio.Shape
For Each shp In shapes
‘ Masterが定義されているシェイプなら登録
If Not shp.Master Is Nothing Then
If Not dict.Exists(shp.Master.Name) Then
dict.Add shp.Master.Name, True
End If
End If
‘ グループ化されたシェイプの再帰探索
If shp.Shapes.Count > 0 Then
Call ScanShapesForMasters(shp.Shapes, dict)
End If
Next
End Sub
—
3. シニアエンジニアが意識すべき「落とし穴」
A. 逆順ループの絶対原則
Visioに限らず、VBAのコレクション操作において`For Each`での削除は御法度だ。インデックスの整合性が崩壊し、予期せぬ実行時エラーを引き起こす。必ず `For i = Count To 1 Step -1` を用いること。
B. COMオブジェクトのメモリリーク
VisioのオブジェクトはCOMを経由する。大規模な処理を行う際、ループ内でオブジェクト変数を安易に再利用しすぎると、メモリ解放が遅延し、Visio自体のクラッシュを誘発する。特に`Shapes`コレクションへのアクセスは重いため、可能であればキャッシュを活用せよ。
C. 組み込みマスターの保護
`mst.Hidden`プロパティや、特定のライブラリに属するステンシルを削除しようとするとVBAが悲鳴を上げる。削除前には必ず、削除可能なオブジェクトであるかの判定(`IsBuiltIn`属性の確認等)をロジックに組み込む必要がある。
—
4. さらなる高みへ:システム連携とPDF出力
最適化を行った後は、必ず`doc.SaveAs`で別名保存するか、あるいは`SaveAsEx`を用いて保存オプションを制御せよ。
また、PDF出力を行う際は、`doc.ExportAsFixedFormat`を使用するが、最適化直後にPDF出力を行うと、レイアウト計算のキャッシュが効いていないために出力が遅くなる場合がある。 一度ファイルを閉じ、再オープンしてから出力する「ワンクッション」を置くのが、システム自動化における安定稼働の秘訣だ。
—
結びに代えて:完璧主義のその先へ
このツールを導入することで、数MB単位の削減は容易に達成できる。しかし、真のアーキテクトは「削除する」ことよりも「不要なものを増やさない」設計を重視する。
マスターシェイプを乱立させるユーザー教育、あるいはステンシルを共有サーバーで一元管理する構成管理。これらと組み合わせることで初めて、貴方のシステムは「伝説的」と呼ぶにふさわしい堅牢性を手に入れる。
コードを書き換える際は、常に「これが10万シェイプあるファイルでも耐えうるか?」を自問自答せよ。それこそが、現場を渡り歩くエンジニアの矜持である。
