【VBAリファレンス】VBAサンプル集VBAコードの全プロシージャー・プロパティ一覧を取得

スポンサーリンク

VBAプロジェクトの全コードを紐解く:プロシージャー・プロパティ一覧取得の技術的アプローチ

Excel VBAを用いた大規模な開発において、避けて通れない課題が「コードの可視化」です。複数のモジュール、クラス、ユーザーフォームが混在するプロジェクトにおいて、どのモジュールにどのようなプロシージャー(Sub/Function)が定義されており、どのようなプロパティが設定されているかを把握することは、保守性やデバッグ効率に直結します。

本稿では、VBAそのものを用いて、VBAプロジェクト内の全コンポーネント、その中の全プロシージャー、そしてプロパティ情報をプログラム的に抽出する高度な手法を解説します。

VBEオブジェクトモデルの活用

VBAでコードを解析するためには、VBA拡張ライブラリである「Microsoft Visual Basic for Applications Extensibility 5.3」を参照設定する必要があります。このライブラリを活用することで、VBE(Visual Basic Editor)の内部構造を操作し、コードの内容を動的に読み取ることが可能になります。

具体的には、以下の階層構造を理解する必要があります。
1. VBProject: プロジェクト全体を指すルートオブジェクト
2. VBComponents: 標準モジュール、クラスモジュール、フォームなどのコレクション
3. CodeModule: 各コンポーネントに含まれる実際のソースコード文字列

このモデルを活用すれば、単にファイル名を取得するだけでなく、コードの行数、プロシージャーの開始行、終了行、さらには宣言文の内容までを精緻に取得できます。

詳細解説:コード解析のロジック

コードのプロシージャー一覧を取得する際、最もシンプルかつ強力な手法は「CodeModule」オブジェクトの「ProcOfLine」メソッドと「ProcStartLine」メソッドを組み合わせることです。

各モジュールのコードを1行ずつ走査し、その行がどのプロシージャーに属しているかを判定します。既に処理済みのプロシージャーはスキップすることで、重複のない一覧を作成します。また、プロパティ情報については、主にユーザーフォームのコントロールやクラスモジュールのProperty定義を対象としますが、これらは「ProcBodyLine」や「ProcCountLines」プロパティを駆使することで、そのブロックの全容を特定できます。

特に注意すべき点は、VBAの「信頼性」設定です。このコードを実行するためには、Excelの「セキュリティセンター」設定にて「VBAプロジェクトオブジェクトモデルへのアクセスを信頼する」にチェックを入れる必要があります。これがオフの状態では、プログラムからのコード解析は一切拒否されます。

サンプルコード:全プロシージャー抽出ツール

以下のサンプルコードは、アクティブなブック内の全標準モジュール、クラスモジュール、ユーザーフォームを走査し、イミディエイトウィンドウにその情報を出力するプロシージャーです。


' 参照設定: Microsoft Visual Basic for Applications Extensibility 5.3
Sub ExportAllProcedureList()
    Dim vbProj As VBIDE.VBProject
    Dim vbComp As VBIDE.VBComponent
    Dim codeMod As VBIDE.CodeModule
    Dim lineNum As Long
    Dim procName As String
    Dim procType As VBIDE.vbext_ProcKind
    Dim lastProcName As String
    
    Set vbProj = ThisWorkbook.VBProject
    
    Debug.Print "プロジェクト名: " & vbProj.Name
    Debug.Print "----------------------------------------"
    
    For Each vbComp In vbProj.VBComponents
        Set codeMod = vbComp.CodeModule
        lineNum = codeMod.CountOfDeclarationLines + 1
        
        Debug.Print "モジュール: " & vbComp.Name
        
        Do While lineNum < codeMod.CountOfLines
            procName = codeMod.ProcOfLine(lineNum, procType)
            
            If procName <> "" And procName <> lastProcName Then
                Debug.Print "  - プロシージャー名: " & procName & _
                            " (型: " & GetProcKindName(procType) & ")"
                lastProcName = procName
            End If
            
            ' 次のプロシージャーへスキップ
            lineNum = codeMod.ProcStartLine(procName, procType) + _
                      codeMod.ProcCountLines(procName, procType)
        Loop
        lastProcName = ""
    Next vbComp
End Sub

Function GetProcKindName(kind As VBIDE.vbext_ProcKind) As String
    Select Case kind
        Case vbext_pk_Proc: GetProcKindName = "Sub/Function"
        Case vbext_pk_Let: GetProcKindName = "Property Let"
        Case vbext_pk_Set: GetProcKindName = "Property Set"
        Case vbext_pk_Get: GetProcKindName = "Property Get"
    End Select
End Function

実務アドバイス:大規模プロジェクトへの適用

この手法を実務で活用する際、単に一覧を出すだけでは不十分なケースが多いです。以下の視点を取り入れることで、ツールとしての価値が飛躍的に向上します。

1. CSV/Excelへの書き出し: イミディエイトウィンドウへの出力ではなく、新規ワークシートに「モジュール名」「プロシージャー名」「行数」「種類」をリスト化し、ドキュメント化を自動化しましょう。これにより、納品時のコード設計書作成時間を劇的に短縮できます。
2. 依存関係の可視化: プロシージャー名だけでなく、その内部で呼び出されている他のプロシージャー名を正規表現で抽出することで、メソッド間の呼び出し関係(コールグラフ)を作成することも可能です。
3. 未使用プロシージャーの検知: 多くの開発現場で、長年放置された「死にコード」が問題となります。全一覧を抽出した上で、特定のプロジェクト内で一度も検索に引っかからないプロシージャーを抽出するロジックを組めば、コードの断捨離が可能になります。
4. エラーハンドリングの徹底: 複雑なプロジェクトでは、保護されたモジュールや読み取り専用のコンポーネントが存在する場合があります。ループ処理内では必ず On Error Resume Next 等を使用して、予期せぬ停止を防ぐ設計にしてください。

まとめ:VBAを「ブラックボックス」にしないために

VBAは、その手軽さゆえに、いつの間にか巨大で複雑なスパゲッティコードになりがちです。今回紹介した「VBAプロジェクトの内部構造をプログラムで解析する」という手法は、単なる便利ツール作成の域を超え、エンジニアとしての「コード品質への責任」を果たすための重要なスキルです。

VBAのコードを「文字列」として扱い、解析し、整理する能力を身につければ、自分自身が書いたコードだけでなく、他者が作成したレガシーなコードを読み解く際にも、圧倒的なスピードで全容を把握できるようになります。

ぜひ本稿のサンプルをベースに、ご自身の開発環境に合わせたカスタマイズを行ってください。コードの可視化は、効率的な開発の第一歩です。日々のコーディングにおいて、常に「このプロジェクトを第三者が解析するならどうすべきか」という視点を持つことが、ベテランエンジニアへの近道となります。

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