【テクニカル・上級編】ScreenUpdating = False実行時の例外処理:画面描画フリーズを防ぐTry-Catch-Finally風パターン – Visio VBA解析バイブル

スポンサーリンク

Visio VBAの「沈黙」を制御せよ:ScreenUpdating = False における堅牢な例外処理の極意

Visio VBAで数千のシェイプを操作する際、`Application.ScreenUpdating = False` を記述するのは定石だ。しかし、多くのジュニアエンジニアはこの「魔法の呪文」を唱えた後、復旧の術を忘れる。エラーでコードが停止すれば、Visioは画面を更新しないまま「ゾンビ状態」で放置される。ユーザーは画面が固まったと勘違いし、タスクマネージャでVisioを強制終了させる。

これはコードの瑕疵ではない。アーキテクチャの敗北だ。

今回は、大規模なVisio自動化システムにおいても絶対に画面をフリーズさせない、堅牢なTry-Catch-Finallyパターンの実装を伝授する。

1. なぜ「単純なエラーハンドラ」では不十分なのか

VBAには標準で `Try…Catch` 構文がない。多くの開発者は `On Error GoTo ErrorHandler` を使うが、複雑なネストや再帰呼び出しを含むVisioのイベント処理において、スタックの巻き戻し中に描画フラグの再有効化を忘れるケースが後を絶たない。

特に、`Application` オブジェクトのプロパティは、Visioの描画スレッドと密接に結びついている。エラー発生時にスタックを正しくクリアし、必ず `ScreenUpdating = True` を通る「唯一の出口」を保証しなければならない。

2. 堅牢な例外処理の実装テンプレート

以下のコードは、あらゆるVisio自動化の基盤となるべき「ゴールデンパターン」である。

‘ — Visio自動化のアーキテクチャ・テンプレート —
Public Sub ProcessVisioAutomation()
Dim isUpdating As Boolean

‘ 事前準備:現在の状態を保持
isUpdating = Application.ScreenUpdating

On Error GoTo CleanUp

‘ 描画の停止:パフォーマンスの極限を追求する
Application.ScreenUpdating = False

‘ — メインの業務ロジック —
‘ ここにシェイプ操作やドキュメント処理を記述する
Call PerformComplexOperations
‘ —————————-

CleanUp:
‘ エラーの有無にかかわらず、必ず実行される終了処理
‘ オブジェクトの解放と描画状態の復元を保証する
Application.ScreenUpdating = isUpdating

‘ エラーが発生していた場合はここで再送出する
If Err.Number <> 0 Then
Dim errDesc As String
errDesc = “Visio Automation Error: ” & Err.Description
‘ 必要に応じてWindows Event Logへの書き出し等のロギングを行う
Debug.Print errDesc
Err.Raise Err.Number, “ProcessVisioAutomation”, errDesc
End If
End Sub

このパターンの要諦

1. 状態の保存と復元: `isUpdating = Application.ScreenUpdating` とすることで、元の状態が何であったかを問わず、呼び出し元の設定を破壊しない。
2. CleanUpラベルの一元化: `Resume` を使用せず、`GoTo` で必ず `CleanUp` を通るフローにする。これにより、どの段階でエラーが起きても描画更新が保証される。
3. 例外の再送出: `Err.Raise` を利用し、上位モジュールにエラーを伝播させる。エラーを握りつぶすのはバグの温床となる。

3. シニアエンジニアのための最適化:メモリとリソースの管理

Visioのオブジェクトモデルは、COM(Component Object Model)のラッパーである。`Page.Shapes` をループで回す際、オブジェクト変数を適切に破棄しなければ、メモリリークとパフォーマンス低下が同時に発生する。

オブジェクトの明示的解放

VBAのガベージコレクションを待つ余裕はない。大規模処理では以下の作法を徹底せよ。

Dim shp As Visio.Shape
For Each shp In ActivePage.Shapes
‘ 処理内容

‘ ループ内での明示的解放
Set shp = Nothing
Next shp

Windows APIによる「強制再描画」の補完

稀に、`ScreenUpdating = True` を実行してもVisioが描画をサボることがある。その場合は、`User32.dll` を呼び出し、ウィンドウの再描画を強制的に依頼する。

If VBA7 Then
Private Declare PtrSafe Function InvalidateRect Lib “user32” (ByVal hwnd As LongPtr, ByVal lpRect As LongPtr, ByVal bErase As Long) As Long
End If

‘ 描画更新後に呼び出す
InvalidateRect Application.WindowHandle32, 0, 1

4. 終わりに:アーキテクトの矜持

Visio VBAはレガシーとされることが多いが、適切に設計された自動化ツールは、今なおエンタープライズの現場で圧倒的な生産性を叩き出す。

「画面がフリーズした」というクレームは、エンジニアの敗北宣言だ。コードの裏側で何が起きているか、COMオブジェクトがどのようにリソースを占有しているか。それらを深く理解し、予期せぬエラーという「死」をコードの一部として受け入れ、美しく復旧させる設計こそが、我々エンジニアが目指すべき地平である。

さあ、コードを書け。ただし、完璧な出口を準備してからだ。

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