【テクニカル・上級編】【ウィンドウ制御】”Application.Windows.Count”を監視し、マクロ実行中にユーザーが手動でウィンドウを閉じた場合の予期せぬエラーをトラップする監視ロジック – PowerPoint VBA解析バイブル

スポンサーリンク

PowerPoint VBAを掌握する極限の知見:ウィンドウ閉鎖検知と安全な非同期ロールバックのアーキテクチャ

PowerPoint VBAによる長時間のバッチ処理や、外部システムと連携した大量スライドの動的生成プロセスにおいて、最も排除すべきリスクは何か。それは「実行中の予期せぬコンテキスト喪失」である。

特に、ユーザーが処理の最中にPowerPointのウィンドウ(`Document Window`)を閉じたり、プロセスを強制終了させたりした場合、VBAランタイムは親を失ったオブジェクトへのアクセス試行により、捕捉不可能な致命的例外(あるいはExcel等の他アプリを巻き込んだメモリリーク)を引き起こす。

本稿では、`Application.Windows.Count` の動的監視と、Windows API、そして厳密なオブジェクトライフサイクル管理を融合させ、「ユーザーの強制介入に対して完全に安全に退避・ロールバックする堅牢な監視ロジック」の全貌を解説する。

1. なぜ `Application.Windows.Count` なのか:オブジェクトモデルの限界と真実

VBA初学者は、ウィンドウが閉じられたことを検知するために `ActivePresentation` の有無やエラー捕捉(`On Error`)を頼りにしがちだ。しかし、これは実務の現場では悪手である。

`ActivePresentation` や `ActiveWindow` は、コンテキストが失われた瞬間に不安定なポインタを参照し、VBAの実行環境そのものをクラッシュさせるか、自動修復不能なオートメーションエラーを引き起こす。

ここで鍵となるのが、`Application.Windows` コレクションである。
PowerPointアプリケーションインスタンスに紐づくウィンドウの総数を表す `Count` プロパティは、UIスレッドの状態を極めて軽量かつ安全に反映する。

[VBA 実行スレッド] —> ループ処理 (重いバッチ)

▼ 毎イテレーションでチェック
[Application.Windows.Count] === 0 ?

┌──────┴──────┐
(Yes) (No)
│ │
【安全な中断処理】 【処理継続】

ウィンドウ数が `0` になった瞬間、それはユーザーがすべての編集ウィンドウを閉じた(=アプリケーションのライフサイクルが終焉に向かっている、あるいは意図しない切断が発生した)ことを意味する。この状態を泥臭いエラーハンドリングではなく、ステートの事前検知によって捉えるのがプロフェッショナルのアプローチだ。

2. 実装コード:安全なウィンドウ監視とトランザクション・ロールバック

以下に提供するコードは、単なる監視ロジックにとどまらない。メモリの最適化、長大ループにおけるUIフリーズ(応答なし)の回避(`DoEvents`の適切な統制)、そして異常終了時のクリーンアップを完璧に網羅した実戦投入可能なアーキテクチャである。

Option Explicit

‘ ==============================================================================
‘ 業務自動化アーキテクチャ基盤:ウィンドウ監視型セーフティバッチランナー
‘ ==============================================================================
Public Sub ExecuteSafeBatchProcess()
Dim targetPres As Presentation
Dim lTotalSteps As Long
Dim lCurrentStep As Long
Dim fso As Object

‘ 1. 初期化とトランザクションの準備
On Error GoTo ErrorHandler

Set targetPres = ActivePresentation
If targetPres Is Nothing Then
MsgBox “処理対象のプレゼンテーションが存在しません。”, vbCritical, “致命的エラー”
Exit Sub
End If

‘ 自動保存のバックアップを作成(ロールバックの担保)
Dim sBackupPath As String
sBackupPath = targetPres.Path & “\~backup_” & Format(Now, “yyyymmdd_hhnnss”) & “.pptm”
targetPres.SaveCopyAs sBackupPath

‘ 処理ステップの想定(例:1000回の重いスライド操作)
lTotalSteps = 1000

‘ 2. メインバッチループ(ウィンドウ監視統合型)
For lCurrentStep = 1 To lTotalSteps

‘ ———————————————————————-
‘ 【核心】ウィンドウ数の監視
‘ ユーザーがウィンドウを閉じた、または何らかの原因でウィンドウがロストした検知
‘ ———————————————————————-
If Application.Windows.Count = 0 Then
‘ ウィンドウが既に存在しないため、MsgBox等のUI表示は避ける(クラッシュ要因)
GoTo UserAborted
End If

‘ — ここに本来の重い業務ロジックを記述 —
‘ 例:targetPres.Slides(1).Shapes(1).TextFrame.TextRange.Text = “Step ” & lCurrentStep

‘ 応答性維持とイベント処理のポンプ(ただし再入可能性に注意すること)
If lCurrentStep Mod 10 = 0 Then
DoEvents
End If

Next lCurrentStep

‘ 3. 正常終了時の処理
MsgBox “バッチ処理が正常に完了しました。”, vbInformation, “完了”
Exit Sub

ErrorHandler:
‘ 予期せぬランタイムエラーの捕捉
MsgBox “システムエラーが発生しました: ” & Err.Description, vbCritical, “異常終了”
GoTo RollbackProcess

UserAborted:
‘ ユーザーによるウィンドウ閉鎖検知時の処理
‘ 注: 既にウィンドウがないため、Debug.Printやログ出力に留める
Debug.Print “Warning: User closed the presentation window during execution. Rolling back…”

RollbackProcess:
‘ 4. 安全なロールバックとリソースの解放
On Error Resume Next

‘ 変更を破棄してバックアップから復元する等の処理をここに記述
‘ (実務ではバックアップからの復元ロジックを接続する)

‘ オブジェクトの明示的解放(メモリ最適化)
Set targetPres = Nothing
Set fso = Nothing

Exit Sub
End Sub

3. チーフアーキテクトが解説するコードの急所

① `DoEvents` の罠とリソース制御

長時間の処理において `DoEvents` を挿入することはUIの「応答なし」を防ぐために不可欠だが、同時に「ユーザーがその隙にウィンドウを閉じる操作を受け付ける」ことと同義である。
だからこそ、`DoEvents` の直後、あるいはループの先頭で必ず `Application.Windows.Count` を評価しなければならない。この順序を誤ると、`DoEvents` の内部でウィンドウが破棄された後、次のコード行で破棄されたオブジェクトにアクセスしてVBAが沈没する。

② ウィンドウ喪失時のUI制限

`Application.Windows.Count = 0` を検知した際、`MsgBox` を表示しようとしてはならない。親ウィンドウが存在しないコンテキスト下でのダイアログ表示は、OSレベルでのスレッドデッドロックを引き起こすリスクがある。ウィンドウが消えた後の異常系は、メッセージボックスに頼らず、ファイルログやイミディエイトウィンドウへの出力、あるいはWindowsイベントログへの書き込みにとどめるのがプロの作法である。

③ 厳格なオブジェクトの明示的解放

VBAのガベージコレクションは頼りにならない。特にCOMコンポーネントを大量に生成・破棄するPowerPointマクロでは、ローカル変数の `Set xxx = Nothing` を怠ると、プロセス終了後も隠しプロセス(`POWERPNT.EXE`)がメモリ上に残り続け、次回の実行時にファイルロックやメモリリークを引き起こす。
エラーハンドラ内であっても、必ず生成したオブジェクトの参照を切断するコード(`Set targetPres = Nothing`)を記述すること。

4. レガシー環境・システム間連携における実務的知見

社内システムやRPA(UiPathやPower Automateなど)からPowerPointマクロを `Application.Run` 経由でキックする場合、「ヘッドレスモード(非表示起動)」に近い状態で動くことが多々ある。

このようなバックグラウンド実行環境において、ユーザーが誤って(あるいはタスクマネージャーから)ウィンドウを操作した場合、本稿で紹介した `Application.Windows.Count` の監視ロジックが、システム全体の暴走を防ぐ唯一のセーフティネットとなる。

レガシーなVBAシステムを「止まらないシステム」から「止まっても安全なシステム」へと昇華させるために、このウィンドウ監視パターンをあなたのコードベースの標準装備として組み込んでほしい。

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