【実務・中級編】フォームのTimerIntervalとOnTimerで実現するバックグラウンドでの擬似マルチスレッド処理 – Access VBA解析バイブル

スポンサーリンク

Access VBAで「擬似マルチスレッド」を制御せよ:TimerIntervalが切り拓く非同期処理の極意

Access開発の現場で、一度は絶望した経験がないだろうか。「重いデータ処理を走らせた途端、画面がフリーズし、Windowsから『応答なし』の宣告を受ける」。

Accessはシングルスレッドで動作する宿命にある。しかし、業務自動化のプロフェッショナルであれば、この制約を「言い訳」にしてはならない。今回は、`TimerInterval`と`OnTimer`イベントを駆使し、メインスレッドを殺さずに重い処理を小分けに実行する「擬似マルチスレッド(タスク・スケジューリング)」の設計思想を伝授する。

1. なぜ「同期処理」が現場の地雷になるのか

VBAでループ処理を回す際、`DoEvents`を挟む手法は一般的だが、あれはあくまで「OSに制御権を一時的に返す」だけの場当たり的な対処だ。多用すれば処理速度は低下し、ユーザーが誤ってフォームを閉じればアプリは強制終了(クラッシュ)する。

真のアーキテクトは、「状態保持(State Management)」を実装する。処理を「分割可能な単位」に分解し、Timerイベントが定期的に「次はどこまでやったか?」を確認して実行する。この設計こそが、堅牢なバックグラウンド処理の要諦である。

2. 堅牢な実装:ステートマシンによるタスク制御

今回の実装では、クラスモジュールのような設計思想をフォームに持ち込む。重要なのは「処理の状態」を保持する変数をフォームモジュールレベルで定義することだ。

実装コード:BackgroundTaskForm

このフォームを「非表示」あるいは「ステータス表示用」として裏で動かすことで、メイン画面を操作不能にすることなく重い処理を完遂させる。

Option Compare Database
Option Explicit

‘ 処理状態を保持するプライベート変数
Private m_TaskStep As Long
Private m_IsRunning As Boolean

‘ フォームロード時にタイマーを停止状態で待機
Private Sub Form_Load()
Me.TimerInterval = 0
m_TaskStep = 0
m_IsRunning = False
End Sub

‘ 外部から処理を開始させるトリガー
Public Sub StartHeavyTask()
If m_IsRunning Then Exit Sub

m_IsRunning = True
m_TaskStep = 1
Me.TimerInterval = 100 ‘ 100ms間隔でポーリング開始
End Sub

‘ タイマーイベントによる擬似マルチスレッド実行
Private Sub Form_Timer()
On Error GoTo Err_Handler

‘ 処理を分割して実行(ステートマシン)
Select Case m_TaskStep
Case 1
‘ ステップ1: データの準備・検証
Debug.Print “Step 1: データの検証中…”
m_TaskStep = 2

Case 2
‘ ステップ2: 重い外部ファイル読み込みやAPI通信
Debug.Print “Step 2: 重い処理を実行中…”
‘ ※ここでDoEventsは不要。Timerがインターバルを管理するため
m_TaskStep = 3

Case 3
‘ ステップ3: DB更新・クリーンアップ
Debug.Print “Step 3: 完了処理中…”
Me.TimerInterval = 0 ‘ 処理終了、タイマー停止
m_IsRunning = False
MsgBox “処理が完了しました。”, vbInformation

End Select
Exit Sub

Err_Handler:
Me.TimerInterval = 0
m_IsRunning = False
MsgBox “エラー発生: ” & Err.Description, vbCritical
End Sub

3. 実務で勝つための「3つの鉄則」

コードをコピペするだけでは一流にはなれない。現場でバグを生まないための「境界条件」を意識せよ。

① 「状態」の排他制御を徹底せよ

`m_IsRunning`フラグを必ず用意すること。ユーザーがボタンを連打しても、処理が二重に走り出す(レースコンディション)を物理的に防がなければならない。

② エラーハンドリングの「タイマー停止」

`OnTimer`内でエラーが発生した際、`TimerInterval`を`0`に戻さなければ、エラーダイアログが無限に表示され続ける「地獄のループ」に陥る。必ずエラーハンドラー内に停止処理を記述せよ。

③ データベース連携の注意点

長時間かけてデータを更新する場合、`CurrentDb`を使い回すのではなく、`DAO.Database`オブジェクトを明示的にオープン・クローズし、トランザクションを適切に制御すること。特にネットワークドライブ上のDBでこれを行う際は、コネクションのライフサイクルに細心の注意を払え。

結論:Accessの制約を「設計のスパイス」に

Accessは本来、RADツールとしての側面が強い。しかし、今回のような「Timerによるスケジューリング」を導入することで、高度な非同期処理システムへと昇華させることができる。

「重い処理をどうさばくか」という問いは、プログラミングの本質だ。Accessという閉じた環境でも、脳の使い方次第で無限の拡張性が手に入る。さあ、このコードを武器に、あなたの業務アプリケーションをワンランク上のプロダクトへと引き上げてほしい。

エンジニアの諸君、コードに妥協するな。

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