【テクニカル・上級編】Application.VBEオブジェクトを用いた、モジュール内のプロシージャ名一括取得とドキュメント化 – Access VBA解析バイブル

スポンサーリンク

VBEを完全掌握せよ:`Application.VBE`オブジェクトによるプロシージャ自動列挙と極限のドキュメント化

レガシーシステムの暗部。それは、前任者が遺した「動くが誰も中身を知らないAccessデータベース」である。
何万行ものスパゲッティコード、場当たり的なエラーハンドリング、そして一切更新されない仕様書。この負債を前にしたとき、手作業でコードを読み解くのはエンジニアの寿命を削るだけの愚行だ。

我々はコードを書くだけのプログラマーではない。システムを支配するアーキテクトである。
今回は、Accessの内部心臓部である `Application.VBE` オブジェクトを直接叩き、モジュール内のプロシージャ(Sub / Function)を網羅的に抽出し、ドキュメント化を完全自動化する手法を解説する。

VBAのメタプログラミング領域に踏み込む。覚悟のある者だけについてきてほしい。

1. 踏み越えてはならない領域:VBE操作の前提条件

`Application.VBE`(Visual Basic for Applications Environment)を操作するということは、IDE(統合開発環境)のメモリ空間に直接干渉することを意味する。ここには通常のVBAコーディングとは異なる、厳格なルールが存在する。

必須のセキュリティ設定

VBEオブジェクトモデルをプログラムから制御するには、Accessのセキュリティ設定で以下の壁を突破しておかなければならない。
1. 「Visual Basic プロジェクトへのプログラムからのアクセスを信頼する」 の有効化(TrustAccessVBOM)。
これを怠ると、実行瞬間に `エラー 1004` またはそれに類するオートメーションエラーが叩きつけられる。
2. 参照設定の追加:
VBEオブジェクトを安全かつ強固に扱うためには、VBAコードから `VBIDE` ライブラリを明示的にバインドする必要がある。

2. アーキテクチャ設計:メモリリークを根絶する参照の作法

VBEオブジェクトモデルは、COM(Component Object Model)の塊である。
`VBComponent` や `CodeModule` といったオブジェクトを巡回する際、適切な解放を行わなければ、Accessのプロセス内にメモリリークが蓄積し、最悪の場合はAccessそのものがクラッシュする。

チーフアーキテクトとして、以下の鉄則を遵守するコードを書く。

  • オブジェクト変数の完全なスコープ管理と `Nothing` 代入
  • 早期バインディング(Early Binding)による型安全性の確保

まずは、VBEの参照設定(Microsoft Visual Basic for Applications Extensibility 5.3)をコード内で動的に検証しつつ、安全にプロシージャ名を取得するコアエンジンを実装する。

3. 実装:プロシージャ自動列挙・ドキュメント化エンジン

以下のコードは、現在のデータベース内に存在するすべての標準モジュール、クラスモジュール、フォーム/レポートのコードモジュールを走査し、そこに定義されているすべてのプロシージャ名(Sub / Function / Property)、スコープ(Public / Private)、およびコード行数を抽出するスクリプトである。

‘ ==============================================================================
‘ Module: modVBEInspector
‘ Description: VBEオブジェクトを用いたコード解析・ドキュメント自動生成エンジン
‘ Architecture: Early Binding (Requires Microsoft Visual Basic for Extensibility 5.3)
‘ ==============================================================================
Option Explicit

Public Sub ExportProcedureInventory()
‘ 事前準備: [ツール] -> [参照設定] から “Microsoft Visual Basic for Applications Extensibility 5.3” を有効化すること

Dim vbProj As VBIDE.VBProject
Dim vbComp As VBIDE.VBComponent
Dim codeMod As VBIDE.CodeModule

Dim wsOut As Worksheet ‘ ※Excel連携する場合を想定、またはテーブル出力に改変可能
Dim targetDb As DAO.Database
Dim rsOut As DAO.Recordset

Dim i As Long
Dim lineNum As Long
Dim procName As String
Dim procKind As VBIDE.vbext_ProcKind

On Error GoTo ErrorHandler

‘ 1. VBEプロジェクトの取得
Set vbProj = Application.VBE.ActiveVBProject

‘ 2. 出力先テーブルの初期化(Access内テーブル “T_ProcedureInventory” に出力する設計)
Set targetDb = CurrentDb
targetDb.Execute “DELETE FROM T_ProcedureInventory;”, dbFailOnError
Set rsOut = targetDb.OpenRecordset(“T_ProcedureInventory”, dbOpenTable)

‘ 3. コンポーネント(モジュール、フォーム等)の走査
For Each vbComp vbProj.VBComponents
Set codeMod = vbComp.CodeModule
lineNum = 1

Do While lineNum < codeMod.CountOfLines ' 4. 次のプロシージャ名を取得 procName = codeMod.GetProcOfLine(lineNum, procKind) If procName <> “” Then
‘ レコードの書き込み
rsOut.AddNew
rsOut!ModuleName = vbComp.Name
rsOut!ModuleType = GetModuleTypeName(vbComp.Type)
rsOut!ProcedureName = procName
rsOut!ProcedureType = GetProcKindName(procKind)
rsOut!StartLine = lineNum
rsOut!LineCount = codeMod.GetProcLines(procName, procKind)
rsOut.Update

‘ 次のプロシージャの先頭行へジャンプ
lineNum = lineNum + codeMod.GetProcLines(procName, procKind)
Else
‘ プロシージャに属さない宣言部などの場合、1行進める
lineNum = lineNum + 1
End If
Loop

‘ COMオブジェクトの解放(メモリ管理の徹底)
Set codeMod = Nothing
Set vbComp = Nothing
Next vbComp

MsgBox “プロシージャインベントリの作成が完了しました。”, vbInformation, “VBEインスペクター”
GoTo Cleanup

ErrorHandler:
MsgBox “予期せぬエラーが発生しました: ” & Err.Description, vbCritical, “Critical Error”
Resume Cleanup

Cleanup:
‘ 明示的なオブジェクト解放によるメモリリークの根絶
If Not rsOut Is Nothing Then rsOut.Close: Set rsOut = Nothing
If Not targetDb Is Nothing Then Set targetDb = Nothing
Set vbProj = Nothing
End Sub

‘ ==============================================================================
‘ ヘルパー関数: モジュールタイプの文字列変換
‘ ==============================================================================
Private Function GetModuleTypeName(ByVal mType As VBIDE.vbext_ComponentType) As String
Select Case mType
Case vbext_ct_StandardModule: GetModuleTypeName = “標準モジュール”
Case vbext_ct_ClassModule: GetModuleTypeName = “クラスモジュール”
Case vbext_ct_MSForm: GetModuleTypeName = “ユーザーフォーム”
Case vbext_ct_Document: GetModuleTypeName = “ドキュメント(Form/Report)”
Case Else: GetModuleTypeName = “不明”
End Select
End Function

Private Function GetProcKindName(ByVal pKind As VBIDE.vbext_ProcKind) As String
Select Case pKind
Case vbext_pk_Proc: GetProcKindName = “Sub/Function”
Case vbext_pk_Let: GetProcKindName = “Property Let”
Case vbext_pk_Get: GetProcKindName = “Property Get”
Case vbext_pk_Set: GetProcKindName = “Property Set”
Case Else: GetProcKindName = “Unknown”
End Select
End Function

4. チーフアーキテクトの洞察:なぜこの手法が実務で神格化されるのか

単にプロシージャ名を取るだけなら、テキストファイルにエクスポートして正規表現でパースする手もある。しかし、`Application.VBE` を使うことには決定的なアドバンテージがある。

1. リアルタイム性: ファイルをエクスポートするI/Oオーバーヘッドがなく、インメモリで瞬時に解析が完了する。
2. 構造的把握: 単なる文字列ではなく、`CodeModule.GetProcOfLine` といったVBEネイティブのAPIを使うことで、コメントや空白行に惑わされず、正確な「プロシージャの境界」と「行数(肥大化の指標)」を割り出せる。
3. リファクタリングのロードマップ化: 抽出したデータを基に、「行数が300行を超えているスパゲッティ関数(Code Smells)」をSQLで一網打尽に抽出し、技術的負債のヒートマップを描くことができる。

レガシーシステムを恐れるな。システムがどれほど巨大で泥臭くても、その構造はコードで書かれている以上、コードの力で完全に掌握できる。

VBAの限界を嘆く前に、提供されたオブジェクトモデルの深淵を使い切れ。それがプロフェッショナルの仕事である。

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