【入門編】Application.CurrentProject.AllFormsを利用した、存在しないフォームへのアクセスを未然に防ぐ防御的プログラミング – Access VBA解析バイブル

スポンサーリンク

こんにちは!現場でバリバリ動くシステムを作るのは楽しい反面、予期せぬエラーで止まってしまうと冷や汗をかきますよね。特に「存在しないフォームを開こうとしてVBAが強制終了した……」なんて経験はありませんか?

マクロの記録から一歩進み、本格的なAccess VBAの書き手を目指すあなたへ。
今回は、Accessオブジェクトモデルの核心に迫り、「エラーが起きる前に防ぐ」防御的プログラミングの極意を伝授します。

ここをクリアすれば、あなたの書くプログラムは見違えるほど堅牢(ロバスト)になりますよ。さあ、一緒に本質をマスターしていきましょう!

1. なぜ「存在しないフォームへのアクセス」でVBAは爆発するのか?

Accessでフォームを操作する時、私たちはよく次のようなコードを書きます。

‘ 【危険な例】存在するかどうかわからないフォームをいきなり操作する
DoCmd.OpenForm “frm_SalesDetail”

もし、この `frm_SalesDetail` というフォームがデザインの変更で削除されていたり、名前が `frm_売上詳細` に変わっていたりしたらどうなるでしょうか?

VBAの実行エンジンはパニックを起こし、お馴染みの「実行エラー ‘2450’: Microsoft Access は、式で参照されている ‘frm_SalesDetail’ フォームを見つけ出せません。」という冷酷なエラーダイアログを表示して処理を中断します。

ユーザーがこれを目撃した瞬間、システムへの信頼は地に落ちます。プログラミング初学者が最初に陥る罠が、この「存在確認をせずに命令してしまう」ことなのです。

2. 救世主:`Application.CurrentProject.AllForms` とは何か?

ここで登場するのが、Accessオブジェクトモデルの重要パーツである `Application.CurrentProject.AllForms` コレクション です。

「コレクション」と聞くと難しく聞こえるかもしれませんが、要するに「現在このAccessファイルに含まれている、すべてのフォームの集合知(名簿)」だと思ってください。

この名簿(AllForms)のすごいところは、「実際にフォームを開かなくても、そこにあるかどうかを事前に名前でチェックできる」という点です。

図解イメージ

[CurrentProject.AllForms コレクション]
┣ “frm_Menu” (あ、存在するぞ)
┣ “frm_MasterInput” (存在するぞ)
┗ “frm_SalesDetail” (…あれ、名簿にないぞ?) => 事前に検知!

開いていない状態のフォームであっても、名簿に名前があるかを照合することで、エラーを未然に防ぐ「防御壁」を作ることができます。

3. 実践!安全なUI制御のコード実装

それでは、実際に現場でそのまま使える、堅牢なプログラミングを書いてみましょう。
今回は、「指定したフォームがプロジェクト内に存在するかチェックし、存在する場合のみ開く」というスマートなプロシージャを作成します。

以下のコードを、標準モジュールにそのままコピペして試してみてください。

‘ ===================================================================
‘ プロシージャ名: SafeOpenForm
‘ 概要: 指定されたフォームの存在を事前に確認し、安全に開く
‘ 引数: formName (String) – 開きたいフォームの名前
‘ ===================================================================
Public Sub SafeOpenForm(ByVal formName As String)

‘ 1. フォーム名が空っぽでないかチェックする(基本的な防御)
If Trim(formName) = “” Then
MsgBox “フォーム名が指定されていません。”, vbExclamation, “入力値エラー”
Exit Sub
End If

‘ 2. AllFormsコレクションを利用して、フォームの存在を事前確認
If IsFormLoadedOrExists(formName) Then
‘ 存在することが確認できたので、安全に開く
DoCmd.OpenForm formName
MsgBox “フォーム [” & formName & “] を正常に開きました。”, vbInformation, “成功”
Else
‘ 存在しない場合の親切なハンドリング
MsgBox “指定されたフォーム [” & formName & “] は見つかりませんでした。” & vbCrLf & _
“開発者にお問い合わせください。”, vbCritical, “存在確認エラー”
End If

End Sub

‘ ===================================================================
‘ 関数名: IsFormLoadedOrExists
‘ 概要: AllFormsコレクションを走査し、フォームが存在するか判定する
‘ 戻り値: Boolean (存在する: True / 存在しない: False)
‘ ===================================================================
Private Function IsFormLoadedOrExists(ByVal formName As String) As Boolean

Dim obj As AccessObject
Dim isFound As Boolean

isFound = False

‘ AllFormsコレクションから一つずつフォームを取り出してチェック
For Each obj In Application.CurrentProject.AllForms
If obj.Name = formName Then
isFound = True
Exit For ‘ 見つかったのでループを抜け出す(パフォーマンス配慮)
End If
Next obj

‘ 判定結果を返す
IsFormLoadedOrExists = isFound

End Function

4. チーフアーキテクトが教える、プロのワンポイントアドバイス

上記のコードだけでも十分に安全ですが、さらにワンランク上のプログラミングを目指すための「知見」を共有しておきます。

① `IsLoaded` プロパティとの混同に注意する

Access VBAには、`CurrentProject.AllForms(“フォーム名”).IsLoaded` というプロパティもあります。これは「そのフォームが今現在、画面上に開かれているか(イネーブル状態か)」を調べるものです。

  • `AllForms` コレクションの有無確認:フォームのデザイン自体がデータベース内に「存在するか」を調べる。
  • `IsLoaded` プロパティ:フォームが「起動中か」を調べる。

この2つを混同すると、「存在しないフォームを開こうとしてエラー」のループから抜け出せなくなります。まずは今回のテーマである存在そのものの確認を確実に行えるようにしましょう。

② マクロからの脱却とモジュール化のメリット

「ボタンを押したらフォームを開く」という処理を、マクロや各フォームのイベントに直接ベタ書き(ハードコーディング)すると、フォーム名が変わった時にすべての箇所を修正しなくてはなりません。

今回のように、安全チェックを行う共通関数(ラッパー関数)を一つ作っておけば、フォーム名が変わっても修正は一箇所で済みます。これが保守性の高いシステムの設計思想です。

まとめ

今回は `Application.CurrentProject.AllForms` を利用した、存在しないフォームへのアクセスを防ぐ防御的プログラミングを解説しました。

  • エラーを後からキャッチするのではなく、起きる前に防ぐのがプロの流儀。
  • `Application.CurrentProject.AllForms` を使えば、開いていないフォームの存在も事前にチェックできる。
  • 親切なメッセージを返すことで、ユーザーフレンドリーなシステムになる。

ここをクリアできれば、あなたのAccess VBAスキルは間違いなく初級者のステージを脱却し、中級エンジニアの扉を開いています。ぜひ、明日の開発現場から取り入れてみてくださいね。それでは、また次回の知見でお会いしましょう!

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