こんにちは!Access VBAの世界へようこそ。
マクロの自動記録を卒業し、VBAコードを使って複雑な処理に挑戦し始めると、必ず一度はぶつかる「壁」があります。
それは、「大量のデータを処理している最中に、Accessの画面が真っ白になり『応答なし』になってしまう問題」です。
せっかく便利にしようと作ったツールなのに、処理が終わるまで画面がフリーズして進捗もわからない…これではユーザーも不安になってしまいますよね。
今回は、このフリーズ地獄から抜け出すための最強の特効薬、ADO(ActiveX Data Objects)の「非同期処理(`adAsyncExecute`)」について分かりやすく解説します!
ここをクリアできれば、あなたのAccess VBAのスキルは「初心者」から「プロレベルの実践者」へと大きく跳ね上がりますよ。一緒に楽しく学んでいきましょう!
—
1. なぜ画面はフリーズするのか?(同期処理 vs 非同期処理)
普段、私たちがVBAでクエリを実行するとき、Accessは「同期処理(Synchronous)」という方法で動いています。
これは、「クエリの実行命令を出したら、データベースから返事が来るまでVBAはすべての仕事をストップしてじっと待つ」という動きです。
【同期処理 (Synchronous)】
[ユーザー操作] —> [クエリ実行開始]
│
▼ (データベースが処理中…)
【VBAも画面描画も完全にストップ!】
【画面が白くなり「応答なし」が発生】
│
[結果受信] <-----------┘
[画面更新] ---> ユーザー「やっと終わった…」
これに対して、今回挑戦する「非同期処理(Asynchronous)」は違います。
クエリ実行命令を出した瞬間に、VBAはデータベースに「あとは裏でやっておいてね!」と任せて、すぐに自分の制御を取り戻します。
【非同期処理 (Asynchronous)】
[ユーザー操作] —> [非同期クエリ実行命令 (adAsyncExecute)]
│
├─────────────────────────────┐
▼ ▼
[バックグラウンドでDB処理] [VBAの制御が即座に戻る!]
│ │
│ [画面に「処理中…」と表示]
│ [プログレスバーを動かす]
│ [キャンセルボタンを受け付ける]
▼ │
[DB処理が完了!] │
│ │
└────────► [完了イベント発生] ◄┘
│
[「完了しました!」と表示]
つまり、重い処理をバックグラウンド(裏側)で動かしつつ、表側のUI(ユーザーインターフェース)はサクサク動かせるようにするのが非同期処理なのです。
これを実現するために使うのが、ADOというデータアクセステクノロジーと、そのオプションである `adAsyncExecute` です。
—
2. 実践準備:ADOを使うための参照設定
Access標準の「DAO」はAccess標準データベース(ACEエンジン)と直結していてシンプルですが、このような高度な非同期イベント処理はADOの得意分野です。
まず、VBAエディタ(ALT + F11)を開き、メニューの [ツール] > [参照設定] を確認しましょう。
- Microsoft ActiveX Data Objects 6.1 Library(バージョンは2.8等でも可)
こちらにチェックを入れて [OK] を押してください。これでADOを使う準備は完了です!
—
3. コード解説:非同期処理を実装してみよう!
非同期処理を実現するためのポイントは次の2つです。
1. `WithEvents` キーワードを使う(DBからの「終わったよ!」という通知を受け取るため)
2. クエリ実行時に `adAsyncExecute` フラグを渡す
フォームのモジュールに以下のコードを貼り付けて試してみてください。
(フォームに `btnRun` というボタンと、`lblStatus` というラベルを配置した前提のコードです)
Option Explicit
‘ ==============================================================================
‘ 【重要ポイント1】 WithEventsキーワード
‘ モジュールレベルで WithEvents を付けて宣言することで、
‘ ADO接続オブジェクト(cn)が発生させるイベント(完了通知など)をVBAで受け取れるようになります。
‘ ==============================================================================
Private WithEvents cn As ADODB.Connection
‘ フォームが開いたとき
Private Sub Form_Load()
Me.lblStatus.Caption = “待機中…”
Me.btnRun.Enabled = True
End Sub
‘ 実行ボタンが押されたとき
Private Sub btnRun_Click()
Dim strConnectionString As String
Dim strSQL As String
On Error GoTo ErrorHandler
‘ 1. UIの表示を「処理中」に変更し、二重押しを防ぐためにボタンを無効化
Me.lblStatus.Caption = “バックグラウンドでクエリを実行中…”
Me.btnRun.Enabled = False
‘ 2. 接続文字列の作成(自分自身のAccessデータベースへ接続する場合)
strConnectionString = “Provider=Microsoft.ACE.OLEDB.12.0;Data Source=” & CurrentDb.Name
‘ 3. Connectionオブジェクトの生成と接続
Set cn = New ADODB.Connection
cn.Open strConnectionString
‘ 4. 意図的に時間がかかるSQL(大容量テーブルの集計など)を設定
‘ ※環境に合わせてご自身のテーブル名・SQLに書き換えてください
strSQL = “SELECT Count() FROM T_LargeData;”
‘ ==========================================================================
‘ 【重要ポイント2】 adAsyncExecute オプション
‘ 第3引数に adAsyncExecute を指定することで、クエリを「非同期」で実行します。
‘ VBAはこの行を実行した直後、処理の終わりを待たずに次の行へ進みます!
‘ ==========================================================================
cn.Execute strSQL, , adAsyncExecute
‘ ここで一旦Subを抜けますが、クエリは裏で元気に動いています!
Exit Sub
ErrorHandler:
MsgBox “エラーが発生しました: ” & Err.Description, vbCritical
Me.btnRun.Enabled = True
Me.lblStatus.Caption = “エラー終了”
End Sub
‘ ==============================================================================
‘ 【重要ポイント3】 イベントハンドラー
‘ バックグラウンドのクエリ処理が「完了」した瞬間に、ADOがこのSubプロシージャを自動的に呼び出します。
‘ ==============================================================================
Private Sub cn_ExecuteComplete(ByVal RecordsAffected As Long, _
ByVal pError As ADODB.Error, _
adStatus As ADODB.EventStatusEnum, _
ByVal pCommand As ADODB.Command, _
ByVal pRecordset As ADODB.Recordset, _
ByVal pConnection As ADODB.Connection)
‘ エラーの有無をチェック
If adStatus = adStatusErrorsFailed Then
Me.lblStatus.Caption = “処理中にエラーが発生しました: ” & pError.Description
Else
Me.lblStatus.Caption = “処理が正常に完了しました!(影響件数: ” & RecordsAffected & “件)”
End If
‘ 完了したのでボタンを再度有効化
Me.btnRun.Enabled = True
‘ 後片付け:接続を閉じる
If Not cn Is Nothing Then
If cn.State = adStateOpen Then cn.Close
Set cn = Nothing
End If
End Sub
—
4. 初心者が陥りやすい「3つの落とし穴」と対策
非同期処理はとても強力ですが、仕組みを理解していないとハマってしまう罠があります。先輩エンジニアとして、あらかじめ対策をお伝えしておきますね!
① 変数のスコープ(生存期間)の罠
`Private WithEvents cn As ADODB.Connection` は、必ずモジュールの先頭(宣言部)で宣言してください。
`btnRun_Click` の中で `Dim cn As New ADODB.Connection` と宣言してしまうと、`btnRun_Click` が終わった瞬間に `cn` 変数が消滅してしまい、バックグラウンド処理の完了通知(`ExecuteComplete`)を受け取れなくなってしまいます。
② エラーハンドリングの場所が違う!
通常のコードでは `btnRun_Click` 内の `On Error GoTo` でエラーを捕まえます。
しかし、非同期処理実行中に起きたデータベースのエラー(SQL構文エラーなど)は、`cn_ExecuteComplete` イベント側の引数 `pError` に引き渡されます。完了イベント側でエラー判定を行うのがプロの鉄則です。
③ ユーザーの「連打」を防ぐ
非同期処理中は画面が固まらないため、ユーザーがボタンをもう一度押せてしまいます。処理が二重に走るとデータベースがロックされたり動作が重くなったりするため、実行直後にボタンの `.Enabled = False` にして無効化する癖をつけましょう。
—
まとめ:非同期処理をマスターして、ワンランク上のAccessアプリへ!
お疲れ様でした!今回はADOの `adAsyncExecute` を使った非同期処理の基本と実践をお伝えしました。
- 同期処理:画面がフリーズし、「応答なし」になりやすい。
- 非同期処理:`adAsyncExecute` でバックグラウンド実行し、画面を快適に保つ。
- `WithEvents`:裏での処理が終わったタイミングを `ExecuteComplete` イベントでスマートに検知する。
この技術を使えば、「処理中にくるくる回るアニメーションを表示する」「進捗状況を表示する」「途中でキャンセルできるようにする」といった、まるで市販の洗練されたアプリケーションのようなWeb風UIをAccessで実現できるようになります。
ここをクリアできれば、Access VBAの基礎・応用はバッチリです!
ぜひあなたの開発現場のツールに取り入れて、ユーザーを「おおっ!フリーズしない!」と驚かせてみてくださいね。応援しています!
