Visio VBAで実現する完全サイレントなバッチ処理:Application.ShowChangesとUI非表示による超高速自動処理
一般的なExcel VBAの感覚でVisioの自動化コードを書くと、ほぼ例外なく「処理の遅さ」と「不安定さ」という壁にぶち当たります。
画面が激しく明滅し、大量の図面を処理している最中に「保存しますか?」というダイアログが表示されて処理が完全にストップする。あるいは、バックグラウンド処理のはずがタスクバーにVisioが次々と立ち上がり、最終的にはメモリを食いつぶして強制終了する――これらはすべて、Visioオブジェクトモデルの特性を理解していないために起こる典型的な不具合です。
本稿では、数百枚から数千枚のVisio図面を完全にバックグラウンドで一括処理(PDF変換、テキスト置換、整合性検証など)するための、「完全サイレントかつ超高速なバッチ処理テンプレート」を解説します。
単なるリファレンスの引き写しではない、実務の修羅場をくぐり抜けてきたアーキテクチャ設計をその手に入れてください。
—
1. 完全サイレント&高速化を阻む「3つの壁」
Visioのバッチ処理を極限まで高速化・安定化させるには、以下に示す3つの技術的ボトルネックを完全に排除しなければなりません。
壁①:画面描画(フリッカーとレンダリングコスト)
Excelでの `Application.ScreenUpdating = False` に相当するのが、Visioにおける `Application.ShowChanges` です。
しかし、Visioは高度なベクターグラフィックスエンジンを搭載しているため、描画コストがExcelやWordの比ではありません。`ShowChanges = False` を指定せずにシェイプの追加やプロパティ変更を繰り返すと、エンジンはミリ秒単位で画面の再描画(レンダリング)を試み、CPUリソースを限界まで消費します。
壁②:割り込みダイアログ(プロンプトによるハングアップ)
「古いバージョンで作成されたファイルです」「壊れたリンクが含まれています」「保存しますか?」
これらのポップアップダイアログは、人間が操作しているときには親切ですが、深夜に実行する自動バッチ処理においては致命的なシステムストップの要因となります。サイレント処理を実現するためには、すべてのダイアログ応答をコード側で事前制御(スキップ、またはデフォルト応答)する必要があります。
壁③:ゾンビプロセス(COMオブジェクトの解放漏れ)
Visioを非表示(Invisible)で起動して処理を行う際、エラーによってコードが途中でクラッシュすると、タスクマネージャーに `VISIO.EXE` がゴースト(ゾンビプロセス)として残留します。これが何度も繰り返されるとサーバーやPCのメモリが枯渇し、OS全体の動作に深刻な影響を与えます。
「どのようなエラーが起きても、絶対にVisioインスタンスをクリーンに破棄して終了する」という堅牢な例外処理(Try-Catch-Finally構造)が不可欠です。
—
2. 解決への極限アプローチ:InvisibleAppとダイアログ制御
これらの課題を解決するための最強の武器が、`Visio.InvisibleApp` と `AlertResponse` です。
起動時から非表示にする `Visio.InvisibleApp`
多くの開発者は、通常通り `CreateObject(“Visio.Application”)` でインスタンスを生成してから `Visible = False` に設定しようとします。しかし、これでは起動した瞬間に一瞬だけVisioのウィンドウが画面に描画されてしまいます。
正解は、最初から非表示専用のクラスである `Visio.InvisibleApp` をインスタンス化することです。
Set appVisio = CreateObject(“Visio.InvisibleApp”)
この一行だけで、Visioは完全にデスクトップから隠蔽された状態で起動し、無駄なUIコンポーネントの初期化をスキップするため、起動速度自体も大幅に向上します。
警告を完全に握りつぶす `AlertResponse`
ダイアログの発生自体を抑制、あるいは自動応答させるために、以下のプロパティを組み合わせます。
appVisio.AlertResponse = 1 ‘ すべてのダイアログに対して「OK」または「はい」で自動応答
appVisio.ShowChanges = False ‘ 画面更新の完全停止
`AlertResponse` に適切な値をセットすることで、ユーザーの介入を一切必要としない、完全なノンストップ・バッチ処理が可能になります。
—
3. プロダクション品質の完全サイレント・バッチ処理コード
以下に、実務でそのまま利用できる、堅牢極まりないVBAコードを示します。
このマクロは、指定されたフォルダ内にあるすべてのVisioファイル(`.vsdx`, `.vsd`)を完全に非表示で開き、全ページの全シェイプを走査して特定のテキストを置換し、PDFとしてエクスポートした上で、元のファイルを上書き保存せずに閉じるという一連のバッチ処理を行います。
Excel等のVBA標準モジュールに貼り付けて実行してください。
Option Explicit
‘ ==============================================================================
‘ 処理名:ExecuteSilentVisioBatch
‘ 概要:指定フォルダ内の全Visioファイルを完全非表示・警告なしで高速処理する
‘ ==============================================================================
Public Sub ExecuteSilentVisioBatch()
Dim targetFolder As String
‘ ★対象フォルダのパスを指定(末尾にバックスラッシュを付与)
targetFolder = “C:\VisioBatchProcess\TargetFiles\”
Dim fileName As String
fileName = Dir(targetFolder & “.vsd”) ‘ .vsd および .vsdx を対象とする
If fileName = “” Then
MsgBox “対象ファイルが見つかりません。”, vbExclamation, “処理中断”
Exit Sub
End If
‘ 1. Visioアプリケーションのインスタンス化(InvisibleAppによる完全非表示起動)
Dim appVisio As Object ‘ Visio.Application
On Error Resume Next
Set appVisio = CreateObject(“Visio.InvisibleApp”)
On Error GoTo 0
If appVisio Is Nothing Then
MsgBox “Visioの起動に失敗しました。インストール状況を確認してください。”, vbCritical, “エラー”
Exit Sub
End If
‘ 2. 実行環境の極限最適化(警告の抑制と描画の完全停止)
With appVisio
.AlertResponse = 1 ‘ ダイアログにはすべて自動で「OK/はい」を返す
.ShowChanges = False ‘ 描画更新を完全に停止(超高速化の肝)
.EventsEnabled = 0 ‘ ドキュメント開閉時などのイベントマクロを走らせない
End With
‘ ログ用のカウンター
Dim successCount As Long: successCount = 0
Dim failureCount As Long: failureCount = 0
‘ メインループ
Do While fileName <> “”
Dim fullPath As String
fullPath = targetFolder & fileName
‘ 個々のファイル処理に対する堅牢な例外ハンドリング
On Error GoTo FileSkipRecovery
Dim doc As Object ‘ Visio.Document
‘ 読み取り専用、かつ非表示(NoWindow)でドキュメントを開く
‘ 第3引数:visOpenRO (2) + visOpenNoWindow (16) + visOpenMacrosDisabled (128) = 146
Set doc = appVisio.Documents.OpenEx(fullPath, 146)
‘ — [業務ロジック開始] —
‘ 例として、全ページの全シェイプをスキャンし、特定のテキストを検証・置換する
Dim pg As Object ‘ Visio.Page
Dim shp As Object ‘ Visio.Shape
For Each pg In doc.Pages
For Each shp In pg.Shapes
‘ シェイプテキストの置換処理(例: “DRAFT” -> “RELEASED”)
If InStr(shp.Text, “DRAFT”) > 0 Then
shp.Text = Replace(shp.Text, “DRAFT”, “RELEASED”)
End If
Next shp
Next pg
‘ PDFエクスポート処理(同名でPDF保存)
Dim pdfPath As String
pdfPath = Left(fullPath, InStrRev(fullPath, “.”)) & “pdf”
‘ ExportAsFixedFormat の呼び出し
‘ 第1引数: visFixedFormatPDF (1), 第2引数: 出力パス
doc.ExportAsFixedFormat 1, pdfPath, 1, 0 ‘ 標準画質、全ページエクスポート
‘ — [業務ロジック終了] —
‘ 保存せずに閉じる(変更を加えたが、今回はPDF書き出し目的のため破棄、または必要に応じて上書き保存)
‘ 第1引数:SaveChanges = False (保存しない)
doc.Close
Set doc = Nothing
successCount = successCount + 1
Debug.Print “[SUCCESS] 処理完了: ” & fileName
GoNextFile:
On Error GoTo 0
fileName = Dir() ‘ 次のファイルを取得
Loop
‘ 3. 後処理(クリーンアップ)
GoTo Finalize
FileSkipRecovery:
‘ 個別ファイルでエラーが発生した場合は、ログを記録して次のファイルへ進む(プロセス全体を殺さない)
failureCount = failureCount + 1
Debug.Print “[ERROR] 処理失敗: ” & fileName & ” – ” & Err.Description
‘ 開きっぱなしのドキュメントがあれば閉じる
On Error Resume Next
If Not doc Is Nothing Then
doc.Close
Set doc = Nothing
End If
On Error GoTo 0
Resume GoNextFile
Finalize:
‘ 何があっても最後にVisioインスタンスを破棄してメモリを解放する
On Error Resume Next
If Not appVisio Is Nothing Then
appVisio.ShowChanges = True
appVisio.AlertResponse = 0
appVisio.EventsEnabled = 1
appVisio.Quit
Set appVisio = Nothing
End If
On Error GoTo 0
‘ 最終結果報告
Dim resultMsg As String
resultMsg = “バッチ処理が完了しました。” & vbCrLf & _
“成功: ” & successCount & ” 件” & vbCrLf & _
“失敗: ” & failureCount & ” 件”
MsgBox resultMsg, vbInformation, “処理終了”
End Sub
—
4. プロが実践する極限の最適化技術
上記のコードをベースに、さらに大規模な業務システム(数千枚規模)に適用する場合、設計時に考慮すべき極意を伝授します。
① `Documents.OpenEx` の引数を極める
ファイルをただ開くだけの `Documents.Open` を使ってはいけません。バッチ処理では必ず `Documents.OpenEx` を使用し、ビットマスクによる起動オプションを制御します。
- `visOpenRO (2)`: 読み取り専用。他人が開いているファイルでも競合せず、高速に開けます。
- `visOpenNoWindow (16)`: ウィンドウを作らずに開く。描画リソースの消費を極限まで抑えます。
- `visOpenMacrosDisabled (128)`: ファイルに埋め込まれたVBA(ドキュメントマクロ)を実行させない。セキュリティ対策と予期せぬ動作防止に必須です。
これらを足し合わせた値 `146` を引数に渡すのが、バッチ処理におけるデファクトスタンダードです。
② メモリリーク対策と `DoEvents` の適切な挿入
VBAはシングルスレッドで動作するため、数百ファイルを連続処理すると、Windowsのメッセージキューが滞留し、システムが「応答なし」状態に陥ることがあります。これを防ぐために、ループの最後に `DoEvents` を挟みたくなるかもしれません。
しかし、サイレントバッチ処理においては、安易な `DoEvents` の挿入は避けるべきです。`DoEvents` はOSに制御を戻すため、ユーザーがバックグラウンド処理中に他の操作を行う割り込みを許してしまい、予期せぬエラーを引き起こす原因になります。
どうしても処理の進捗をユーザーに示したい場合は、ステータスバーへの出力(`Application.StatusBar`)や、ログファイルへの非同期書き出しに留めるのがプロの設計です。
③ シェイプ操作は「一括処理(GetFormulasU / SetFormulas)」を検討する
もしバッチ処理の内容が「シェイプデータの大量更新(例えば、すべてのシェイプの特定カスタムプロパティを書き換える等)」である場合、シェイプを一つずつループで処理するのは非効率です。
Visioオブジェクトモデルには、複数のセルの数式を一括で取得・設定する `Page.GetFormulasU` および `Page.SetFormulas` メソッドが存在します。
COMのラウンドトリップ(VBAとVisioプロセス間の通信回数)を最小化するため、数百個のシェイプを書き換える際は、これらの配列を用いた一括処理メソッドを導入することで、処理速度がさらに数倍〜数十倍に跳ね上がります。
—
5. まとめ:ツール開発者から「自動化アーキテクト」へ
一般的なVisio操作の延長でマクロを書くレベルから脱却し、「UIを持たない高速なデータ処理エンジン」としてVisioを制御できるようになれば、社内のドキュメント管理やシステム構成図の自動生成レベルは次元が変わります。
今回紹介した以下の3原則:
1. `CreateObject(“Visio.InvisibleApp”)` による無風起動
2. `ShowChanges = False` と `AlertResponse = 1` による完全サイレント化
3. `OpenEx(…, 146)` による非表示・マクロ無効化での安全なファイルオープン
これらを徹底することで、あなたの作成するツールは「たまに止まるマクロ」から「サーバーサイドでも安定稼働するエンタープライズ向けの自動化システム」へと昇華します。堅牢なコードは、開発者としてのあなたの信頼を何よりも強固に担保してくれるはずです。
