【テクニカル・上級編】【上級者向け】VSDXファイル内の不要なステンシルやスタイルを削除し、ファイルサイズを劇的に軽量化する最適化ツール – Visio VBA解析バイブル

スポンサーリンク

【Visio VBA極限最適化】肥大化したVSDXを秒速でスリム化する「未使用リソース完全駆逐」エンジン

レガシーな業務フロー図、あるいは自動生成された数千個のシェイプを持つ巨大なネットワーク図。運用を続けるうちに、VSDXファイルのサイズが数MBから数十MBへと膨れ上がり、挙動が重くなった経験はないだろうか。

Visioのファイル形式(.vsdx)の本質は、内部がZIP圧縮されたXMLパッケージ(Open Packaging Conventions)である。しかし、UI上から不要なシェイプを削除しても、「一度ドキュメントにインポートされたマスターシェイプ(Masters)」や「自動生成されたカスタムスタイル(Styles)」は、メモリおよびストレージ上に亡霊のように残留し続ける。

今回は、Visio VBAの内部構造を知り尽くしたアーキテクトへ向けて、ドキュメント内部を徹底的にスキャンし、参照されていないゴミを容赦なくパージ(駆逐)する実用的な最適化エンジンを公開する。

—

1. なぜVSDXは肥大化するのか? Visioオブジェクトモデルの暗部

Visioのドキュメント(`Document` オブジェクト)は、描画されているページ(`Pages`)のほかに、以下の隠れた肥大化の温床を持っている。

1. `Masters` コレクション(マスターシェイプ)
一度ドキュメント上にドラッグ&ドロップされたシェイプのマスターは、たとえ画面上のシェイプをすべて削除しても、`Document.Masters` に残り続ける。ステンシルからコピーされたマスターは、ファイルサイズを確実に圧迫する。
2. `Styles` コレクション(スタイル)
外部図面からのコピペやマクロによる動的生成を繰り返すと、使われていない無数のカスタムスタイルが蓄積される。
3. COMオブジェクトの参照リーク
VBAによる一括処理を行う際、オブジェクトの解放(`Set obj = Nothing`)を怠ると、Visioのプロセス内に参照が残り、メモリリークや処理速度の著しい低下を引き起こす。

これらをプログラムによって動的に判定し、安全に削除する仕組みを構築する。

—

2. アーキテクチャ設計:安全なパージの原則

単にコレクションをループして削除しようとすると、Visioは決まってエラーを吐く。
「現在使用中のオブジェクトです」 あるいは 「組み込み(Built-in)の要素は削除できません」 という例外だ。

したがって、以下の厳格な条件を満たすものだけを削除対象に選別する必要がある。

  • ビルトイン(標準)スタイルの除外: Visioがあらかじめ用意している基本スタイル(例: `Normal`, `Heading` 等)は削除不可。`Stat` プロパティやビルトインフラグをチェックする。
  • 依存関係の検証: マスターシェイプの場合、現在の図面上のどのページ・どのシェイプからも参照されていないことを数学的に(あるいはコレクションの走査によって)証明しなければならない。

—

3. 実装コード:VSDX完全最適化モジュール

以下のコードは、アクティブなVisioドキュメントを対象に、未使用のマスターおよびスタイルを徹底的に洗い出して削除し、最適化された状態で別名保存(または上書き保存)を行うVBAモジュールである。

Option Explicit

‘ ==============================================================================
‘ 処理名: VSDXファイル最適化エンジン (Ultimate VSDX Optimizer)
‘ 概要 : 未使用のMastersおよびStylesを徹底駆逐し、ファイルサイズを極限まで削減する
‘ ==============================================================================
Public Sub ExecuteVSDXOptimization()
Dim startTime As Double
startTime = Timer

Dim targetDoc As Visio.Document
Set targetDoc = Visio.ActiveDocument

If targetDoc.ReadOnly Then
MsgBox “このドキュメントは読み取り専用です。最適化を中止します。”, vbCritical, “エラー”
Exit Sub
End If

‘ 画面描画と警告を抑制し、処理速度を限界まで引き上げる
With Visio.Application
.ScreenUpdating = False
.EventsEnabled = False
.Interactive = False
End With

On Error GoTo ErrorHandler

Dim deletedMastersCount As Long
Dim deletedStylesCount As Long

Debug.Print “=== 最適化プロセス開始: ” & targetDoc.Name & ” ===”

‘ 1. 未使用スタイルの削除
deletedStylesCount = PurgeUnusedStyles(targetDoc)

‘ 2. 未使用マスターシェイプの削除
deletedMastersCount = PurgeUnusedMasters(targetDoc)

‘ 3. ドキュメントのガベージコレクションを促すための強制保存
targetDoc.Save

‘ パフォーマンス設定の復元
With Visio.Application
.ScreenUpdating = True
.EventsEnabled = True
.Interactive = True
End With

Dim elapsedTime As Double
elapsedTime = Timer – startTime

MsgBox “最適化が完了しました。” & vbCrLf & _
“・削除されたマスター数: ” & deletedMastersCount & vbCrLf & _
“・削除されたスタイル数: ” & deletedStylesCount & vbCrLf & _
“・処理時間: ” & Format(elapsedTime, “0.00”) & ” 秒”, vbInformation, “最適化完了”

Exit Sub

ErrorHandler:
‘ 異常終了時の安全装置:アプリケーション設定を必ず復元
With Visio.Application
.ScreenUpdating = True
.EventsEnabled = True
.Interactive = True
End With

MsgBox “最適化処理中に重大なエラーが発生しました。” & vbCrLf & _
“エラー番号: ” & Err.Number & vbCrLf & _
“詳細: ” & Err.Description, vbCritical, “致命的エラー”

Set targetDoc = Nothing
End Sub

‘ ——————————————————————————
‘ 未使用スタイルのパージ
‘ ——————————————————————————
Private Function PurgeUnusedStyles(doc As Visio.Document) As Long
Dim stls As Visio.Styles
Set stls = doc.Styles

Dim i As Long
Dim count As Long
count = 0

‘ コレクションの削除はインデックスのズレを防ぐため「後ろから前へ(逆順ループ)」回す
For i = stls.Count To 1 Step -1
Dim stl As Visio.Style
Set stl = stls(i)

‘ 組み込みスタイル(BuiltIn)はスキップ
If Not stl.BuiltIn Then
‘ スタイルが何らかのシェイプから参照されているか判定
‘ ※Visioの仕様上、Stylesオブジェクトの参照カウント直接取得は難しいため、
‘ ここでは安全にトラップを張って削除を試みる
On Error Resume Next
stl.Delete
If Err.Number = 0 Then
count = count + 1
Debug.Print ” [スタイル削除成功] ” & stl.Name
End If
On Error GoTo 0
End If

Set stl = Nothing
Next i

PurgeUnusedStyles = count
End Function

‘ ——————————————————————————
‘ 未使用マスターシェイプのパージ
‘ ——————————————————————————
Private Function PurgeUnusedMasters(doc As Visio.Document) As Long
Dim msts As Visio.Masters
Set msts = doc.Masters

Dim i As Long
Dim count As Long
count = 0

‘ マスターシェイプも同様に逆順で走査
For i = msts.Count To 1 Step -1
Dim mst As Visio.Master
Set mst = msts(i)

If Not mst.BuiltIn Then
‘ ページ上のシェイプでこのマスターを使用しているものが存在するかチェック
If Not IsMasterInUse(doc, mst) Then
On Error Resume Next
mst.Delete
If Err.Number = 0 Then
count = count + 1
Debug.Print ” [マスター削除成功] ” & mst.Name
End If
On Error GoTo 0
End If
End If

Set mst = Nothing
Next i

PurgeUnusedMasters = count
End Function

‘ ——————————————————————————
‘ 指定されたマスターシェイプがドキュメント内で使用されているか判定
‘ ——————————————————————————
Private Function IsMasterInUse(doc As Visio.Document, targetMaster As Visio.Master) As Boolean
Dim pg As Visio.Page
Dim shp As Visio.Shape
Dim inUse As Boolean

inUse = False

‘ すべてのページ(通常ページ、バックグラウンドページ)を走査
For Each pg in doc.Pages
For Each shp in pg.Shapes
‘ Masterプロパティを比較(シェイプの元となったマスターが一致するか)
On Error Resume Next
If Not shp.Master Is Nothing Then
If shp.Master.ID = targetMaster.ID Then
inUse = True
Exit For
End If
End If

‘ グループ化されている内部シェイプ(SubShapes)も再帰的にチェックする必要があるが、
‘ ここでは簡略化のためMasterプロパティの合致を見る
On Error GoTo 0
Next shp

If inUse Then Exit For
Next pg

‘ ステンシル内部のマスター同士の依存関係(他のマスターのパーツになっている場合など)も考慮が必要だが、
‘ 実務上はページ内の参照判定で9割以上のゴミを掃き出せる。

IsMasterInUse = inUse
End Function

—

4. エンジニアリングの要点とパフォーマンスチューニング

上記のコードを実運用・大規模エンタープライズ環境で展開するにあたり、以下の設計思想が組み込まれている。

① 画面描画の完全遮断 (`ScreenUpdating = False`)

数千個のオブジェクトを操作する際、VisioのUIが同期して再描画を行っていると、処理時間が何倍にも跳ね上がる。さらに `.Interactive = False` を組み合わせることで、OS側からの割り込みを防ぎ、CPUリソースをVBAの演算に100%集中させる。

② コレクション走査の鉄則:逆順ループ (`Step -1`)

VBAにおいて、コレクションの要素を削除しながら前方からループを回すと、インデックスのズレ(Index Shift)が発生し、必ず処理漏れやランタイムエラーを引き起こす。削除を伴うコレクション操作は、必ず末尾から先頭へ向かう逆順ループで行うこと。これはVBAプログラミングにおける不文律である。

③ エラーハンドリングの境界防御 (`On Error Resume Next`)

VisioのCOM APIは、バージョンや図面の破損状態によって予期せぬエラーコードを返すことがある。システム全体をクラッシュさせないため、削除処理のピンポイントでエラーをトラップし、「削除不可なものはスルーして次に進む」フェールセーフ構造を実装している。

—

5. チーフアーキテクトからの提言

このマクロを定期実行するバッチタスクや、ドキュメント保存時のイベントハンドラ(`DocumentSaved`)に組み込むことで、組織全体で共有されるVisio資産の肥大化を未然に防ぐことが可能だ。

技術とは、ただ動くだけのものではない。
システムのリソースを敬い、冗長性を削ぎ落とし、極限まで洗練されたコードこそが、真に信頼しうるインフラを支える。ぜひ、あなたの開発環境でこの最適化エンジンを組み込み、その圧倒的な軽快さを体感してほしい。

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