Access VBAを掌握する極限の知見:Application.Echoを制する者は、UXとデバッグを制す
開発プロジェクトで最も恐ろしい瞬間の一つは、大量データ処理の最中に予期せぬエラーが発生し、「画面描画が停止したまま(Echo = False)、Accessの操作が一切受け付けられなくなった状態」でフリーズすることだ。
ユーザーは「固まった」と勘違いしてタスクマネージャーから強制終了をかけ、最悪の場合はデータベースが破損する。デバッグしようにも画面が更新されないため、どこでコケたのか視覚的に追うことすらできない。
プロとして稼働する業務システムを作るなら、「エラーが起こうが、強制終了されようが、確実に画面描画を復帰させる仕組み」を担保しなければならない。今回は、Access VBAのオブジェクトライフサイクルを極限まで利用した、絶対に安全なEcho制御クラスの設計思想と実装を伝授する。
—
なぜ従来の `On Error Goto` では不十分なのか?
多くの開発者は、次のようなコードを書く。
Public Sub BadDataProcess()
Application.Echo False
‘ — 処理本体 —
Dim db As DAO.Database
Set db = CurrentDb
db.Execute “qAppend_HeavyData”, dbFailOnError ‘ ここでエラーが起きたら?
Application.Echo True
Exit Sub
ErrorHandler:
MsgBox “エラー発生: ” & Err.Description
Application.Echo True ‘ 忘れがち、あるいはエラーハンドラを通らない脱出路で死ぬ
End Sub
この実装には致命的な欠陥がある。
1. エラーハンドラの記述漏れ: 複雑なプロシージャになると、`Application.Echo True` に到達しないパターンの脱出路が必ず生まれる。
2. イミディエイトウィンドウでの中断: 開発中に `Ctrl + Break` やコード内の `Stop` で実行を中断した場合、`Echo True` は永遠に実行されない。Accessを再起動する羽目になる。
VBAには、ガベージコレクションやデストラクタの概念が希薄だが、「クラスモジュールの終了(Terminateイベント)」だけは例外的に、スコープを抜けるとき(オブジェクトが破棄されるとき)に100%確実に実行されるという鉄の掟がある。
この仕組みをハックし、「画面描画の復帰」をクラスの寿命に完全に同期させる。
—
堅牢な設計:clsEchoController の全体像
クラスモジュールを作成し、名前を `clsEchoController` とする。
コードはこれだけだ。余計なプロパティは持たせない。シンプル・イズ・ビューティフル。
‘ =================================================================
‘ クラス名: clsEchoController
‘ 概要: インスタンスの生存期間中のみ画面描画を停止し、破棄時に確実に復帰させる
‘ =================================================================
Option Explicit
Private m_IsActive As Boolean
‘ — 初期化処理 (インスタンス生成時) —
Private Sub Class_Initialize()
m_IsActive = True
‘ 描画を停止し、パフォーマンスを最大化する
Application.Echo False
End Sub
‘ — 終了処理 (インスタンス破棄時) —
Private Sub Class_Terminate()
‘ スコープを抜けた瞬間、エラーの有無に関わらず必ずここを通る
If m_IsActive Then
Application.Echo True
‘ 必要であればステータスバーのクリアもここで行う
Application.StatusBar = “”
End If
End Sub
‘ — 手動で早期復帰させたい場合のメソッド —
Public Sub Restore()
If m_IsActive Then
Application.Echo True
m_IsActive = False
End If
End Sub
この設計が優れている理由
- スコープ駆動の自動復帰: プロシージャが正常終了しようが、エラーでジャンプアウトしようが、VBAが変数を解放するタイミングで `Class_Terminate` が走り、必ず `Echo True` に戻る。
- デバッグ中の安全性: コードを強制中断(`End`ステートメントや中断)した場合でも、Accessがオブジェクト変数を破棄する過程でTerminateイベントが発火するため、画面が真っ暗なままフリーズする絶望から解放される。
—
プロダクションコードでの実践的活用法
実際の業務ロジック(例:月次データの集計処理)に、このクラスを組み込んでみよう。
‘ =================================================================
‘ モジュール名: mProcMonthlyBatch
‘ 概要: 月次バッチ処理の実行制御
‘ =================================================================
Option Explicit
Public Sub ExecuteMonthlyBatch()
‘ 1. エコー制御クラスをインスタンス化(この瞬間から画面描画が止まる)
Dim echoCtrl As clsEchoController
Set echoCtrl = New clsEchoController
On Error GoTo ErrorHandler
‘ ステータスバーでユーザーに進捗を伝える(Echo=Falseでも表示は可能)
Application.StatusBar = “月次データの初期化中…”
CurrentDb.Execute “DELETE FROM T_TempMonthly”, dbFailOnError
Application.StatusBar = “集計クエリを実行中…”
CurrentDb.Execute “qAppend_MonthlySummary”, dbFailOnError
‘ 処理が正常に完了し、メッセージを出したい場合など、
‘ 処理の途中で「あえて画面を戻したい」時は明示的にメソッドを叩ける
echoCtrl.Restore
MsgBox “月次バッチ処理が正常に完了しました。”, vbInformation, “完了”
Exit Sub
ErrorHandler:
‘ clsEchoControllerがスコープ外に出るため、
‘ このエラーハンドラ内ですでに画面描画は自動復帰している(安全!)
MsgBox “予期せぬエラーが発生しました。” & vbCrLf & _
“エラー番号: ” & Err.Number & vbCrLf & _
“内容: ” & Err.Description, vbCritical, “システムエラー”
‘ ここで Application.Echo True を書く必要は「もうない」
End Sub
—
現場で役立つチーフアーキテクトからの知見
このイディオムを導入するにあたり、現場の開発者からよく出る疑問に先回りして答えておく。
Q1. `Echo False` にする本当のメリットは描画速度だけ?
A. 描画速度(特にフォームやコントロールが再描画されるのを防ぐことによる劇的な速度向上)はもちろんだが、最大のメリットは「ユーザーによる余計な割込み操作の防止」にある。処理中にユーザーが別のボタンを連打したり、フォームを閉じようとしたりするのを防ぐ物理的な防壁になる。
Q2. フォームの再描画抑制 (`Me.Painting = False`) との違いは?
A. `Application.Echo` はAccessアプリケーション全体の描画を止める。一方、`Me.Painting` は特定フォームのみだ。
バックグラウンドで複数フォームをまたぐ一括処理を行う場合や、画面のちらつきを完全に消し去りたい場合は `Application.Echo` の方が強力。ただし、前述の通り「戻し忘れ」の爆弾を抱えやすいため、今回紹介したクラス化が必須となる。
—
まとめ:プロフェッショナルなVBAコードとは
動くだけのコードは素人でも書ける。しかし、「異常系や予期せぬ中断も含めて、絶対にシステムを破綻させない防衛的コード」を書くことこそが、プロのエンジニアとアマチュアを分ける境界線だ。
`Application.Echo` の制御をアドホック(場当たり的)に書くのは、今日で終わりにしよう。
クラスのライフサイクルを信頼し、安全で、保守性が高く、何よりユーザーに優しいAccessシステムを構築してほしい。
