【テクニカル・上級編】保存確認ダイアログを出さずに閉じる:Document.Savedプロパティとサイレントクローズ – Visio VBA解析バイブル

スポンサーリンク

Visio VBAを掌握する極限の知見:保存確認ダイアログを出さずに閉じる技術

Visioのバッチ処理や、バックグラウンドでのドキュメント自動生成パイプラインを構築する際、最も開発者を絶望させる瞬間がある。それは、数千ファイルに及ぶ一括処理の最中、突然画面の前面にポップアップする「変更を保存しますか?」というモーダルダイアログだ。

この予期せぬ割り込みは、完全無人のヘッドレス実行や、Windowsタスクスケジューラによる夜間バッチを完全に沈黙させる。VBAランタイムは人間の操作を待ち続け、プロセスは無限のデッドロックに陥る。

本稿では、Visioのオブジェクトモデルにおける `Document.Saved` プロパティの真の挙動と、メモリリークを根絶するライフサイクル管理を組み合わせ、「絶対にダイアログを出さないサイレントクローズ」を実装するための極限の知見を公開する。

1. Visioオブジェクトモデルにおける「保存状態」のメカニズム

多くの開発者は、`ActiveDocument.Close` を呼び出せば足りると考えている。しかし、Visioのドキュメントエンジンは、ファイルのオープン、プロパティの変更、そしてクローズに至るまで、独自のダーティフラグ(Dirty Flag)管理を行っている。

Document.Saved プロパティの罠

`Document.Saved` は、論理的な真偽値ではない。Visioの内部ステータスレジスタに直結したフラグである。

  • `False`: 最後に保存されてから変更が加えられている。閉じる際にダイアログのトリガーとなる。
  • `True`: 変更がない(または変更されたが保存済みとみなす)。ダイアログをスキップして即座に閉じられる。

ここで重要なのは、プログラム側でシェイプを1つ追加・削除しただけで、このフラグは自動的に `False` に強制書き換えられるという点だ。API側でどれほどエレガントな処理を書いても、 Visioのコアエンジンは「ユーザーが未保存の変更を加えた」と判断し、安全装置としてダイアログを起動する。

したがって、サイレントクローズを成功させるための鉄則はただ一つ。
「ドキュメントを閉じる直前に、意図的に `Saved = True` を叩き込むこと」である。

2. 実装パターン:メモリ最適化とサイレントクローズの融合

大量のVisioファイルを処理するバッチスクリプトでは、ダイアログの抑制と同時に、Comオブジェクトの適切な解放(メモリリークの防止)が命題となる。Visioのプロセス(`visio.exe`)はメモリ食いであり、不適切な参照保持はすぐにOOM(Out of Memory)を引き起こす。

以下に、実務の現場で耐えうる堅牢な一括処理のコードパターンを示す。

Option Explicit

Sub BatchProcessVisioFiles()
Dim fso As Object
Dim targetFolder As String
Dim fileItem As Object
Dim visApp As Visio.Application
Dim visDoc As Visio.Document

‘ 処理対象フォルダのパス(環境に合わせて変更)
targetFolder = “C:\VisioBatch\Target\”

‘ FileSystemObjectによる堅牢なファイル列挙
Set fso = CreateObject(“Scripting.FileSystemObject”)

If Not fso.FolderExists(targetFolder) Then
MsgBox “指定されたフォルダが存在しません。”, vbCritical
Exit Sub
End If

‘ Visioアプリケーションインスタンスの生成(非表示実行の推奨設定)
Set visApp = New Visio.Application
visApp.ScreenUpdating = False 描画を抑制してパフォーマンスを極限まで引き上げる
visApp.Visible = False ‘ バックグラウンド実行

On Error GoTo ErrorHandler

For Each fileItem In fso.GetFolder(targetFolder).Files
If LCase(fso.GetExtensionName(fileItem.Name)) = “vsd” Or _
LCase(fso.GetExtensionName(fileItem.Name)) = “vsdx” Then

‘ ドキュメントを開く(読み取り専用、または必要に応じて書き込み)
Set visDoc = visApp.Documents.Open(fileItem.Path)

‘ — ここに実際の自動化処理を記述 —
‘ 例: すべてのページのタイトルを変更する等の処理
Call ProcessDocument(visDoc)
‘ —————————————-

‘ 【極限の知見】ダイアログを回避するための強制Saved化
‘ 変更を保存して閉じたい場合は visDoc.Save を先に呼ぶ。
‘ 変更を破棄して強制終了(サイレントクローズ)する場合は以下の2行のみで十分。
visDoc.Saved = True
visDoc.Close

‘ ループ内でのオブジェクト参照の即座破棄(メモリリーク対策)
Set visDoc = Nothing
End If
Next fileItem

CleanUp:
‘ 終了処理
If Not visApp Is Nothing Then
visApp.ScreenUpdating = True
visApp.Quit
Set visApp = Nothing
End If
Set fso = Nothing
Exit Sub

ErrorHandler:
MsgBox “予期せぬエラーが発生しました: ” & Err.Description, vbCritical
Resume CleanUp
End Sub

Private Sub ProcessDocument(ByRef doc As Visio.Document)
‘ サンプル処理:ドキュメント内の全シェイプに対して何らかの操作を行う
Dim pg As Visio.Page
Dim shp As Visio.Shape

For Each pg In doc.Pages
For Each shp pg.Shapes
‘ 処理の例(プロパティの書き換えなど)
‘ shp.Text = “Processed”
Next shp
Next pg
End Sub

3. チーフアーキテクトが警鐘を鳴らす「落とし穴」

上記のコードは一見完璧に見えるが、レガシーなVisio環境(Visio 2010〜2016など)や、アドイン(COM Add-in)が絡む環境では、さらに深い考慮が必要になる。

A. アドインによる横槍と「真のダーティ状態」

サードパーティ製のVisioアドインや、ドキュメントに埋め込まれたVBAプロジェクト(Document-VBA)のイベントハンドラ(`Document_ShapeAdded` など)が稼働している場合、コードの実行完了後にドキュメントが再び「ダーティ(未保存)」状態に遷移することがある。

これを完全にねじ伏せるには、ドキュメントを閉じる直前の行に `Saved = True` を配置するだけではなく、アプリケーション全体の警告表示を殺す必要がある。

‘ アプリケーションレベルでの警告ダイアログの完全無効化
visApp.AlertsEnabled = False

‘ 処理&クローズ
visDoc.Saved = True
visDoc.Close

‘ 処理終了後に必ず復元する
visApp.AlertsEnabled = True

`AlertsEnabled = False` を組み合わせることで、Visioエンジンが発するあらゆるモーダルダイアログ(リンク切れの警告、マクロセキュリティの警告など)を物理的にねじ伏せることが可能になる。

B. プロセスのゾンビ化を防ぐための解放哲学

VBAにおいて、`Set visDoc = Nothing` や `Set visApp = Nothing` は単なる「変数への空代入」ではない。COMの参照カウンタ(Reference Counter)をデクリメントする死活問題である。

特に大量ファイルをループで処理する場合、`visDoc` の解放漏れは、数ファイル処理しただけでVisioのCOMサーバーインスタンスを不安定にし、タスクマネージャーに `visio.exe` のゾンビプロセスを残留させる原因となる。
ループの各イテレーションの終わりには、必ずローカル変数としてのドキュメント参照を完全に断ち切らなければならない。

総括

Visio VBAにおけるサイレントクローズの本質は、Visioという肥大化したCOMコンポーネントの「状態機械(State Machine)」をエンジニアの手で完全に掌握することにある。

  • `Saved = True` の強制代入により、コアエンジンの未保存判定をハックする。
  • `AlertsEnabled = False` により、外部要因によるダイアログの割り込みを遮断する。
  • 厳格なオブジェクト参照の破棄により、メモリリークとゾンビプロセスを駆逐する。

この3つの原則を遵守したアーキテクチャであれば、いかなるレガシーなVisioファイル群であっても、完全無人かつ高速なバックグラウンド処理の強靭なパイプラインを構築できる。現場のエンジニア諸賢の健闘を祈る。

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