【上級】Application.AlertResponseの活用:バックグラウンド処理でのダイアログ抑制と自動応答
Visioを使った大規模な図面の一括処理や、外部データベースと連携した自動レイアウト生成ツールを開発していて、次のような絶望感を味わったことはないだろうか。
「夜間バッチで数百枚の図面を自動処理するはずが、出社してみたら『このファイルは読み取り専用です。上書きしますか?』というダイアログで処理が丸一日ストップしていた……」
プログラミングにおいて、予期せぬダイアログ(モーダルウィンドウ)は自動化の最大の敵である。特にVisioのオブジェクトモデルは、ファイルのリンク切れ、古い形式のステンシル、不正なシェイプ操作などにおいて、容赦なくユーザーへの確認を求めて処理を中断する。
今回は、この悪夢を断ち切り、完全な「無人・ノンストップ運用」を実現するための極意――`Application.AlertResponse` を駆使したダイアログ制御のアーキテクチャを伝授する。
—
1. なぜ通常の `DisplayAlerts` では不十分なのか?
多くのVBAプログラマーは、ExcelやAccessの感覚で `Application.DisplayAlerts = False` を記述して満足する。しかし、Visioの深淵を知る者であれば、それが片輪の自動車であることを知っている。
Visioにも `ScreenUpdating` や `LiveDynamics` といった描画・応答制御プロパティはあるが、「Visioがどうしてもユーザーの意思決定を必要とするクリティカルな警告」は、`DisplayAlerts` をバイパスして強制的にポップアップすることがある。
ここで登場するのが `Application.AlertResponse` だ。
AlertResponse のメカニズム
- 概念: ダイアログが表示された際、人間がクリックする代わりに「あらかじめプログラム側で選択肢を予約しておく」仕組み。
- 挙動: Visioが確認ダイアログを表示しようとした瞬間、VBAエンジンが設定された応答値(ID)を代わりに返し、ダイアログを一瞬たりとも表示させずに処理を続行する。
このプロパティを制することが、真の「エンタープライズグレードのVisio自動化」への第一歩となる。
—
2. 堅牢なバックグラウンド処理設計の鉄則
`AlertResponse` は強力だが、諸刃の剣でもある。誤った応答値を設定したままクリティカルなエラーに出くわすと、意図しないデータ上書きや、無限ループ、あるいはサイレントクラッシュを引き起こす。
現場でバグを起こさないための「3つの鉄則」を頭に叩き込んでほしい。
1. スコープの局所化(必ず復元する)
`AlertResponse` はアプリケーション全体の状態を変える。処理の開始時に元の値を退避させ、終了時(およびエラー発生時)には必ず元の状態に戻さなければならない。さもなければ、ユーザーが手動でVisioを操作する際にもダイアログが勝手に自動応答されてしまう。
2. デフォルト値の明示とエラーハンドリング
予期せぬダイアログに対して「常にOK」と答えるのは危険である。想定外の事態が発生した場合は、処理を安全に中断(Abort)する設計を組み込む。
3. ログ・監査証跡の確保
ダイアログを強制抑制するということは、「何が起きていたのか」を目視で確認できなくなることを意味する。抑制された警告は、必ずイミディエイトウィンドウや外部ログファイルに記録(Trace)しなくてはならない。
—
3. 【プロダクションコード】完全自動化バッチ処理の実装例
それでは、実務の現場でそのまま使える、堅牢性と拡張性を兼ね備えたVBAコードを公開しよう。
このコードは、指定フォルダ内の全Visioファイルを読み込み、外部データを更新した上でサイレント保存するシナリオを想定している。
Option Explicit
‘ ==============================================================================
‘ モジュール名: Mdl_BatchProcessor
‘ 概要 : AlertResponseを用いたVisio図面の完全無人バッチ処理エンジン
‘ ==============================================================================
Public Sub ExecuteSilentBatchProcessing()
Dim targetFolder As String
targetFolder = “C:\VisioWorkSpace\TargetFiles\” ‘ 処理対象フォルダ
If Dir(targetFolder, vbDirectory) = “” Then
MsgBox “指定されたフォルダが存在しません: ” & targetFolder, vbCritical
Exit Sub
End If
‘ — 【鉄則1】実行前の環境退避と安全装置のセット —
Dim originalAlertResponse As Long
Dim originalDisplayAlerts As Integer
On Error GoTo ErrorHandler
‘ 現在の状態を退避
originalAlertResponse = Visio.Application.AlertResponse
originalDisplayAlerts = Visio.Application.ShowChanges ‘ 画面更新等の代用
‘ ★核心:ダイアログに対して「ID = 1 (vbOK / Yes相当)」を自動返答するよう予約
‘ ※ VisioのAlertResponseは、ダイアログのボタン押下値(通常 1:OK/Yes, 2:Cancel/No)を取る
Visio.Application.AlertResponse = 1
‘ 画面描画の抑制(パフォーマンス劇的向上)
Visio.Application.ScreenUpdating = False
Dim fileName As String
fileName = Dir(targetFolder & “.vsd”)
Dim processedCount As Long
processedCount = 0
Do While fileName <> “”
Dim fullPath As String
fullPath = targetFolder & fileName
Debug.Print “処理開始: ” & fileName
If ProcessSingleDocument(fullPath) Then
processedCount = processedCount + 1
End If
fileName = Dir() ‘ 次のファイル
DoEvents
Loop
‘ — 正常終了処理 —
Call RestoreEnvironment(originalAlertResponse)
Visio.Application.ScreenUpdating = True
MsgBox “バッチ処理が完了しました。処理ファイル数: ” & processedCount, vbInformation, “自動化完了”
Exit Sub
ErrorHandler:
‘ — 異常終了時のフェイルセーフ —
Call RestoreEnvironment(originalAlertResponse)
Visio.Application.ScreenUpdating = True
MsgBox “予期せぬエラーが発生しました。” & vbCrLf & _
“Error: ” & Err.Number & ” – ” & Err.Description, vbCritical, “致命的エラー”
End Sub
‘ ==============================================================================
‘ 個別ドキュメントの処理ロジック
‘ ==============================================================================
Private Function ProcessSingleDocument(ByVal filePath As String) As Boolean
Dim doc As Visio.Document
Dim isSuccess As Boolean
isSuccess = False
On Error GoTo DocErrorHandler
‘ OpenEx Flagsの解説:
‘ visOpenRO : 読み取り専用で開く(競合回避)
‘ visOpenHidden : 画面を描画せずにバックグラウンドで開く(高速化)
Set doc = Visio.Application.Documents.OpenEx(filePath, visOpenRO + visOpenHidden)
‘ — ここに実際の図面加工・データ連携処理を記述 —
‘ 例: シェイプのプロパティ更新や外部DBからのデータリフレッシュ
Call UpdateShapesData(doc)
‘ 読み取り専用で開いているため、保存時は別名またはそのまま閉じる
‘ ここであえて「上書き確認ダイアログ」が出るような操作を行っても、
‘ AlertResponse = 1 により自動的に「はい」が選択される。
doc.Close
Set doc = Nothing
isSuccess = True
Debug.Print “処理成功: ” & filePath
ProcessSingleDocument = isSuccess
Exit Function
DocErrorHandler:
Debug.Print “【警告】ファイル処理失敗 (” & filePath & “): ” & Err.Description
If Not doc Is Nothing Then
doc.Close visDoNotSaveChanges ‘ 変更を破棄して強制閉鎖
Set doc = Nothing
End If
ProcessSingleDocument = False
End Function
‘ ==============================================================================
‘ シェイプデータ更新のモック(実務に合わせて拡張)
‘ ==============================================================================
Private Sub UpdateShapesData(ByRef targetDoc As Visio.Document)
Dim pag As Visio.Page
Dim shp As Visio.Shape
For Each pag In targetDoc.Pages
For Each shp In pag.Shapes
‘ 例: 特定のカスタムプロパティ(ShapeData)を持つシェイプの値を書き換え
If shp.CellExists(“Prop.Status”, 0) Then
shp.Cells(“Prop.Status”).FormulaU = “””Processed”””
End If
Next shp
Next pag
‘ ※ここでVisioが「データを更新しますか?」等のダイアログを出そうとしても、
‘ AlertResponse が即座に介入するため処理が止まらない。
End Sub
‘ ==============================================================================
林檎を剥いたら元に戻す:環境復元ルーチン
‘ ==============================================================================
Private Sub RestoreEnvironment(ByVal originalValue As Long)
‘ 常にデフォルト値(0 = ダイアログを表示する通常モード)に戻す
Visio.Application.AlertResponse = 0
End Sub
—
4. チーフアーキテクトからの実務アドバイス
このコードをそのまま導入するにあたり、現場のエンジニアに伝えておきたい「現場の罠」が2点ある。
1. AlertResponse の値の罠
Visioのダイアログの種類(OK/Cancel、Yes/No/Cancelなど)によって、どのボタンがどのID(1, 2, 3…)に該当するかは、Microsoftの公式ドキュメントでも網羅しきれていないケースがある。
本番稼働させる前に、必ず「わざとダイアログを出させるテストケース」を作り、`AlertResponse = 1` で意図したボタンが押下されているか(処理が先へ進むか)を検証環境でテストすること。
2. 無限ループとデッドロックの回避
もしダイアログの裏でVisioが「ディスクの空き容量不足」や「ライセンス認証切れ」といった致命的なシステムエラーを起こしている場合、`AlertResponse` で「OK」を返し続けても、無限に同じダイアログループ(ダイアログストーム)に陥る危険性がある。
これを防ぐため、本番バッチではWindowsタスクスケジューラや外部監視プロセス(Watchdog)を併用し、プロセスが無応答になった場合に強制終了できるセーフティネットを必ず張っておくこと。
まとめ
`Application.AlertResponse` は、手動オペレーションの呪縛から開発者を解放し、真の「24時間365日ノンストップ・Visio自動化基盤」を構築するためのマスターキーである。
「ダイアログで止まるかもしれない」という不安要素をコードレベルで完全に排除し、エレガントで強靭なバックグラウンド処理をあなたのプロジェクトに実装してほしい。
