【テクニカル・上級編】Application.Echoを制御する汎用クラス:エラー発生時でも画面描画を確実に復帰させる – Access VBA解析バイブル

スポンサーリンク

Access VBAを掌握する極限の知見:Application.Echoを制御する汎用クラスの設計思想

レガシーシステムの最前線に立ち続けるエンジニアであれば、誰もが一度は経験する悪夢がある。大量のレコード更新や複雑なクエリの連鎖処理中、Accessの画面が激しくちらつき、OSのリソースを食いつぶしながらフリーズする現象だ。

この画面描画の乱れを抑え、実行速度を劇的に向上させるための基本手段が `Application.Echo False` である。しかし、このメソッドには致命的な罠が潜んでいる。処理の途中で予期せぬ実行時エラーが発生し、エラーハンドラの中で `Application.Echo True` に復帰させるコードを通せなかった場合、Accessの画面は永遠に描画を停止したまま凍結する。 ユーザーはUIを失い、タスクマネージャーから強制終了する以外の選択肢を奪われるのだ。

今回は、このリスクを完全に排除し、エラー発生時やイミディエイトウィンドウでの強制中断時であっても、確実かつ安全に画面描画を復帰させる「RAII(Resource Acquisition Is Initialization)イディオムのVBA実装」とも言うべき汎用クラスモジュール設計を解説する。

1. なぜ「通常のError Handler」では不十分なのか

多くの開発者は、以下のような定石通りのエラーハンドリングを記述して満足している。

Sub BadExample()
Application.Echo False

‘ — 何らかの重い処理 —
Dim db As DAO.Database
Set db = CurrentDb
db.Execute “q_HeavyUpdate”, dbFailOnError

Application.Echo True
Exit Sub

ErrorHandler:
MsgBox “エラー発生: ” & Err.Description, vbCritical
Application.Echo True ‘ ここを通らないパスや、コーディングミスがあり得る
End Sub

このアプローチの脆弱性は明白である。
1. メンテナンス性の欠如: すべてのプロシージャに同じボイラープレート(定型コード)を書く必要があり、改修時に `Echo True` の記述漏れが発生する。
2. VBAの強制終了耐性: 実行中に「リセット」ボタンが押されたり、メモリ不足等の致命的エラーでVBAの実行コンテキストが突然破棄された場合、エラーハンドラすらバイパスされて `Echo` は `False` のまま放置される。

これを防ぐ唯一の手段は、「オブジェクトのスコープ(生存期間)とライフサイクルイベント」に描画の復帰を完全に紐付けることである。

2. クラスモジュールによるスコープ管理:`clsEchoGuard` の設計

VBAにはC++のような真のデストラクタは存在しないが、クラスモジュールの `Class_Terminate` イベントを利用することで、オブジェクトがメモリから解放される瞬間(=スコープを抜けた瞬間)に確実なクリーンアップ処理を実行できる。

以下のコードを、プロジェクト内に `clsEchoGuard` という名前のクラスモジュールとして作成してほしい。

実装コード:`clsEchoGuard`

VERSION 1.0 CLASS
BEGIN
MultiUse = -1 ‘True
END
Attribute VB_Name = “clsEchoGuard”
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = False
Attribute VB_Exposed = False
Option Explicit

‘ =========================================================================
‘ クラス名: clsEchoGuard
‘ 概要: Application.Echo のライフサイクルを管理し、スコープアウト時に確実に復帰させる
‘ =========================================================================

Private m_IsActive As Boolean

‘ クラス初期化時にEchoをオフにする
Private Sub Class_Initialize()
On Error Resume Next
Application.Echo False
m_IsActive = (Err.Number = 0)
On Error GoTo 0
End Sub

‘ クラス破棄時(スコープアウト時・エラー終了時含む)に確実にEchoをオンに戻す
Private Sub Class_Terminate()
Me.Release
End Sub

‘ 明示的な解放および安全装置
Public Sub Release()
On Error Resume Next
If m_IsActive Then
Application.Echo True
m_IsActive = False
End If
On Error GoTo 0
End Sub

アーキテクチャのポイント

  • `Class_Initialize` でインスタンス生成と同時に `Application.Echo False` を実行する。
  • `Class_Terminate`(および明示的な `Release` メソッド)で `Application.Echo True` を実行する。
  • VBAの仕様上、プロシージャが終了する(正常終了、エラーによるジャンプ、果ては `Exit Sub` の通過まで)と、そのプロシージャ内で宣言されたローカル変数のスコープは確実に切れ、インスタンスは破棄される。つまり、開発者が `Echo True` を書く必要すらなくなる

3. 実践:極限まで洗練されたプロシージャの実装

この汎用クラスを実際の業務ロジックに組み込むと、コードベースがいかに堅牢かつシンプルになるかを確認しよう。

Sub ProcessMassData()
‘ 描画抑制ガードのインスタンスを生成(この瞬間からEchoがFalseになる)
Dim echoGuard As clsEchoGuard
Set echoGuard = New clsEchoGuard

On Error GoTo ErrorHandler

‘ — 画面描画を停止した状態で高速に処理を実行 —
Dim i As Long
For i = 1.0 To 10000
‘ 重い処理のシミュレーション
CurrentDb.Execute “UPDATE T_Log SET Processed = True WHERE ID = ” & i, dbFailOnError
: Next i

‘ 必要であれば明示的に解放することも可能(通常はスコープ抜けた時点で自動実行)
Set echoGuard = Nothing

MsgBox “処理が正常に完了しました。”, vbInformation
Exit Sub

ErrorHandler:
‘ エラーが発生しても、echoGuard変数がスコープアウトする過程で
‘ Class_Terminateが呼ばれ、Application.Echoは確実にTrueに戻る
MsgBox “予期せぬエラーが発生しました: ” & Err.Description, vbCritical

‘ ここでechoGuardの明示的解放(必須ではないが安全)
Set echoGuard = Nothing
End Sub

4. チーフアーキテクトからの実践的提言:さらなる高みへ

この `clsEchoGuard` パターンを導入することで、UIのフリーズ事故は完全に撲滅される。しかし、レガシーAccessシステムのパフォーマンスを極限まで引き出すためには、さらに以下の知見を組み合わせてほしい。

1. `SysCmd` との組み合わせ:
長時間のバッチ処理では、画面のちらつきを抑える(`Echo` を切る)だけでなく、ステータスバーに進捗を表示することがユーザーエクスペリエンス(UX)の観点から不可欠である。このクラス内に `SysCmd acSysCmdInitMeter` などの処理をカプセル化する拡張も非常に有効だ。

2. オブジェクト変数の早期解放 (Nothing代入):
DAOの `Recordset` や `Database` オブジェクトは、VBAのガベージコレクションに頼らず、使い終わった瞬間に `Set rs = Nothing` でメモリを即時解放せよ。メモリフラグメンテーションを防ぐことが、Accessのクラッシュを防ぐ最大の防御壁となる。

3. エラーハンドリングの徹底:
`On Error GoTo` を適切に配置し、予期せぬ例外時にもデータベースのトランザクションが宙ぶらりんにならないよう、`DBEngine.Rollback` とこの `clsEchoGuard` を連動させる設計こそが、プロフェッショナルなAccess開発者の条件である。

「動けばいい」という妥協を捨て、オブジェクトのライフサイクルを完全に支配すること。それこそが、何十万行ものレコードを扱う巨大なAccessバックエンドシステムを安定稼働させる唯一の道である。

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