Access VBAを掌握する極限の知見:`CurrentProject.AllModules`による動的解析とリファクタリング・エンジン
長年稼働し続けたAccessデータベースの「負債」に直面したことはないだろうか。
前任者が残した数万行のコード、どこから呼ばれているのか分からない共通関数、スパゲッティのように絡み合ったクエリとモジュール群。
「このプロシージャを削除したら、どこかに影響が出るのではないか?」
「特定のAPIを呼び出している箇所を、すべて洗い出したい」
このような現場の絶望的な状況を打破するため、我々シニアエンジニアが頼るべきは、手作業のコードレビューではない。Accessが内包するオブジェクトモデルとVBA自身をハックし、「コードでコードを解析する」というアプローチだ。
今回は、`Application.CurrentProject.AllModules`を駆使し、プロジェクト内の全モジュールを走査・解析して依存関係やキーワードの使用状況を炙り出す、極限まで最適化されたリファクタリング支援ツールの実装方法を解説する。
—
1. アーキテクチャの核心:なぜ `AllModules` なのか
AccessのVBA開発において、コードの塊(標準モジュール、クラスモジュール、フォーム/レポートのコードビハインド)を操作する際、多くのプログラマは `AccessObject` コレクションの扱いを誤る。
ここで重要な前提がある。
「`AllModules` は、プロジェクトに存在するモジュールのメタデータ(存在や名前)を保持しているが、コードのテキストそのものを保持しているわけではない」
コードのテキスト本体(ソースコード)にアクセスするには、VBE(Visual Basic for Editor)のCOMコンポーネントである VBIDE (Microsoft Visual Basic for Applications Extensibility) を召喚する必要がある。
`CurrentProject.AllModules` で対象を正確に特定し、`VBProject` の各コンポーネントからテキストを抽出する。この二段構えのアーキテクチャこそが、堅牢な解析エンジンの土台となる。
—
2. 開発の前提条件:VBEオブジェクトの参照設定
動的解析を行うにあたり、VBAの裏側で動くVBEのオブジェクトモデルを明示的に扱う。
VBEの「ツール」>「参照設定」から、以下のライブラリにチェックを入れておいてほしい。
- Microsoft Visual Basic for Applications Extensibility 5.3
※これを怠ると、コンパイル時に「ユーザー定義型は定義されていません」というエラーに直面することになる。
—
3. 実装:コード解析・リファクタリング支援エンジン
以下に、プロジェクト内の全モジュールを走査し、指定したキーワード(例: 非推奨となったAPIや特定の関数名)が含まれる行を特定してイミディエイトウィンドウに出力する、実戦投入可能なコードを示す。
メモリリークを防ぐためのオブジェクトの明示的解放、およびVBEの安全な操作を網羅したプロフェッショナル・コードだ。
Option Compare Database
Option Explicit
‘ =========================================================================
‘ ódulo名: basCodeAnalyzer
‘ 概要: CurrentProject.AllModules と VBIDE を活用したコード動的解析ツール
‘ =========================================================================
Public Sub AnalyzeModuleCode(ByVal TargetKeyword As String)
Dim prj As VBIDE.VBProject
Dim comp As VBIDE.VBComponent
Dim modItem As AccessObject
Dim codeModule As VBIDE.CodeModule
Dim lineCount As Long
Dim i As Long
Dim codeLine As String
Dim hitCount As Long
‘ 入力値の検証
If Trim(TargetKeyword) = “” Then
MsgBox “検索キーワードが指定されていません。”, vbCritical, “解析エラー”
Exit Sub
End If
‘ VBEのVBProjectを取得(現在のAccessデータベースのプロジェクト)
On Error GoTo ErrorHandler
Set prj = Application.VBE.ActiveVBProject
hitCount = 0
Debug.Print “=== コード解析開始: キーワード [” & TargetKeyword & “] ===”
‘ CurrentProject.AllModules を走査
For Each modItem In CurrentProject.AllModules
‘ 該当モジュールがVBProject内に存在するか確認し、コンポーネントを取得
If IsComponentExists(prj, modItem.Name) Then
Set comp = prj.VBComponents(modItem.Name)
Set codeModule = comp.CodeModule
lineCount = codeModule.CountOfLines
‘ モジュール内の全行を走査(1行目から最終行まで)
For i = 1 To lineCount
codeLine = codeModule.Lines(i, 1)
‘ キーワードが含まれているか判定(大文字小文字を区別しない)
If InStr(1, codeLine, TargetKeyword, vbTextCompare) > 0 Then
hitCount = hitCount + 1
Debug.Print ” [検出] モジュール: ” & modItem.Name & ” (行: ” & i & “)”
Debug.Print ” -> ” & Trim(codeLine)
End If
End For
End If
Next modItem
Debug.Print “=== 解析完了. 検出件数: ” & hitCount &件 ===”
GoTo SafeExit
ErrorHandler:
MsgBox “予期せぬエラーが発生しました: ” & Err.Description, vbCritical, “致命的エラー”
SafeExit:
‘ 【極限の知見】COMオブジェクトの明示的解放
‘ アクセスVBAにおけるVBIDEオブジェクトの解放漏れはVBEのメモリリーク・クラッシュの温床となる
Set codeModule = Nothing
Set comp = Nothing
Set prj = Nothing
Set modItem = Nothing
‘ End Sub
‘ ————————————————————————-
‘ 補助関数: 指定した名前のVBComponentがプロジェクト内に存在するか確認
‘ ————————————————————————-
Private Function IsComponentExists(ByVal prj As VBIDE.VBProject, ByVal compName As String) As Boolean
Dim c As VBIDE.VBComponent
On Error Resume Next
Set c = prj.VBComponents(compName)
IsComponentExists = (Err.Number = 0 And Not c Is Nothing)
Set c = Nothing
On Error GoTo 0
End Function
—
4. シニアエンジニアが知るべき「罠」とパフォーマンス最適化
上記のコードは美しく機能するが、現場のモンスター級のデータベース(数百のフォームと数万行のコード)で実行する場合、いくつかの知見を持っておかなければシステムが耐えられない。
1. 「信頼できるドキュメント」の設定とセキュリティ
近代のAccess(Office 2013以降)において、プログラムからVBEのオブジェクトモデル(`Application.VBE`)へアクセスするには、セキュリティセンターの設定で「Visual Basic プロジェクトへのプログラムからのアクセスを信頼する」にチェックが入っている必要がある。
エンタープライズ環境で展開する場合、このレジストリ設定をグループポリシー(GPO)やインストーラーで制御する設計が不可欠となる。
2. メモリ管理とCOMの参照解放
VBAは自動ガベージコレクションを持つが、背後で動くCOMオブジェクト(特にVBIDE群)は参照カウント方式で管理されている。
上記のコードで `Set codeModule = Nothing` などの明示的な解放を行っているのはそのためだ。これを怠ると、長時間の解析処理やツールの繰り返し実行によってAccessインスタンスがメモリリークを起こし、最悪の場合はVBEごと強制終了する。
3. パフォーマンスの限界を見据えた非同期・バッチ処理の思想
ループ内で `CodeModule.Lines` を1行ずつ取得する処理は、コード行数が数万行を超えるとわずかに入出力のオーバーヘッドが生じる。
本番用の本格的なリファクタリングツールを構築する場合は、一度全コードを巨大な文字列変数(またはテキストファイル)に一括ダンプし、VBScriptの `RegExp`(正規表現オブジェクト)を用いてメモリ上で高速パターンマッチングを行うアプローチに昇華させるべきだ。
—
5. おわりに:レガシーの支配者となれ
Accessは「古い技術」と揶揄されることがある。だが、その内部構造を深く理解し、VBAとCOMの境界線を熟知したエンジニアの手にかかれば、どんなに複雑怪奇なレガシーシステムであっても完全に掌握し、意のままにリファクタリングすることが可能だ。
今回紹介した `CurrentProject.AllModules` と VBIDE を組み合わせた動的解析手法は、単なるコード検索ツールに留まらない。データベースの自動ドキュメント生成、コーディング規約の自動監査、さらには他システム連携時の依存関係マップ作成など、あなたの開発・保守における強力な武器となるはずだ。
技術を恐れるな。コードの隅々まで支配下に置き、真のアーキテクトとしての手腕を振るってほしい。
