モジュール、プロシージャの一覧を取得

VBAのモジュール、プロシージャの一覧を取得する。

VBAで作成した関数やクラスの情報が管理ができるように指定したブックにあるモジュール、プロシージャの一覧を取得する方法です。
コード情報の取得にはVBComponentsコレクションを利用しており、標準モジュール、クラス、フォーム、Excelオブジェクトで作成したコードの各情報をコレクションから取得させています。

サンプルコードでは下記の情報を取得して一覧化していています。
 ・モジュール名
 ・モジュールタイプ
 ・プロシージャ名
 ・プロシージャ種類
 ・スコープ
 ・プロシージャの開始行
 ・プロシージャの構成行数(コメントや空行を含めた行数)

※実行時に「プログラミングによる Visual Basic プロジェクトへのアクセスは信頼性に欠けます」のエラーメッセージが表示された場合

'******************************************************************************
' プロシージャ・プロパティ一覧を作成
'******************************************************************************
Sub makeProcList()

    Dim wbObj As Workbook
    Set wbObj = ThisWorkbook  '対象のブックを設定

    '他のブックを参照したい場合は下記のように記載、読み取り後はCloseさせる
    'Set wbObj = Workbooks.Open("D:\VBA\マクロ確認.xlsm")
    
    Dim rtnAryProcInfo() As Variant
    Call getProcInfo(wbObj, rtnAryProcInfo)

    'wbObj.Close
    
    '取得した情報をシートに展開
    Dim i As Long
    With Sheets("Sheet1")
        .Cells.Clear
        For i = 0 To UBound(rtnAryProcInfo, 2)
            .Cells(i + 1, 1) = rtnAryProcInfo(0, i)
            .Cells(i + 1, 2) = rtnAryProcInfo(1, i)
            .Cells(i + 1, 3) = rtnAryProcInfo(2, i)
            .Cells(i + 1, 4) = rtnAryProcInfo(3, i)
            .Cells(i + 1, 5) = rtnAryProcInfo(4, i)
            .Cells(i + 1, 6) = rtnAryProcInfo(5, i)
            .Cells(i + 1, 7) = rtnAryProcInfo(6, i)
        Next
    End With
    
End Sub

'******************************************************************************
' モジュール、プロシージャの情報を取得する
'-----------------------------------------------------------------------------
'  第1引数:対象のワークブックオブジェクト
'  第2引数:取得情報の配列(戻り値用)
'******************************************************************************
Sub getProcInfo(getWB As Workbook, ByRef rtnAryProcInfo As Variant)

    ReDim vAryMdlInfo(6, 0) As Variant
    
    '情報のヘッダ(項目名)を配列に設定
    vAryMdlInfo(0, 0) = "モジュール名"
    vAryMdlInfo(1, 0) = "モジュールタイプ"
    vAryMdlInfo(2, 0) = "プロシージャ名"
    vAryMdlInfo(3, 0) = "プロシージャ種類"
    vAryMdlInfo(4, 0) = "スコープ"
    vAryMdlInfo(5, 0) = "開始行"
    vAryMdlInfo(6, 0) = "STEP数"
    
    Dim k As Long '配列要素数
    k = 1         '情報を格納する配列要素数の開始値
    
    Dim i As Long 'モジュールのカウント
    For i = 1 To getWB.VBProject.VBComponents.Count
        Dim sMdlName As String
        sMdlName = getWB.VBProject.VBComponents(i).Name
        
        'モジュールを参照できるようにする
        Dim oVBC  As Object
        Set oVBC = getWB.VBProject.VBComponents(sMdlName).CodeModule
        
        'モジュールのタイプ名を取得
        Dim sProcType  As String
        sProcType = fncGetMdlTypeName(getWB.VBProject.VBComponents(sMdlName).Type)
            
        Dim j As Long 'コード行のカウント
        j = 1         'コードの行開始位置
        Do While j <= oVBC.CountOfLines 'コード末端までループで読み取り
            Dim iProcKind As Long
            If oVBC.ProcOfLine(j, iProcKind) <> "" Then
                
                'プロシージャ名取得
                Dim sProcName As String
                sProcName = oVBC.ProcOfLine(j, iProcKind)
                
                'コード整形(行連結文字("_")で接続部分を結合して1行にする)
                Dim sShpCode As String
                sShpCode = fncShpProcCode(j, oVBC)
                
                'カレントの行がプロシージャ定義行であれば処理
                If fncChkProcLine(sShpCode, sProcName) Then
                    '行数の取得
                    Dim lProcBd  As Long
                    Dim lProcst  As Long
                    Dim lProcCt  As Long
                    lProcBd = oVBC.ProcBodyLine(sProcName, iProcKind)
                    lProcst = oVBC.ProcStartline(sProcName, iProcKind)
                    lProcCt = oVBC.ProcCountLines(sProcName, iProcKind)

                    'プロシージャの種類名を取得
                    Dim sProcKind  As String
                    sProcKind = fncGetProcKindName(iProcKind, sShpCode)
                    
                    ReDim Preserve vAryMdlInfo(6, k)
                    vAryMdlInfo(0, k) = sMdlName    'モジュール名
                    vAryMdlInfo(1, k) = sProcType   'モジュールタイプ名
                    vAryMdlInfo(2, k) = sProcName    'プロシージャ名
                    vAryMdlInfo(3, k) = sProcKind   'プロシージャ種類
                    vAryMdlInfo(4, k) = fncGetScope(fncShpProcCode(j, oVBC))    'スコープ
                    vAryMdlInfo(5, k) = lProcBd 'プロシージャ開始行
                    vAryMdlInfo(6, k) = lProcCt - (lProcBd - lProcst)   '構成行数
                    k = k + 1
                End If
            End If
            j = j + 1
        Loop
    Next

    '取得した情報(配列)を返す
    rtnAryProcInfo = vAryMdlInfo

End Sub

'******************************************************************************
' モジュールのタイプ名を取得
'-----------------------------------------------------------------------------
'  第1引数:モジュールタイプ(数値)
'-----------------------------------------------------------------------------
'  戻り値 :モジュールタイプ(文字列)
'******************************************************************************
Function fncGetMdlTypeName(getType As Long) As String
    
    Select Case getType
        Case 1
            fncGetMdlTypeName = "標準モジュール"
        Case 2
            fncGetMdlTypeName = "クラス"
        Case 3
            fncGetMdlTypeName = "フォーム"
        Case 100
            fncGetMdlTypeName = "Excel Object"
        Case Else
            fncGetMdlTypeName = "(Unknown)"
    End Select

End Function

'******************************************************************************
' プロシージャの種類名を取得
'-----------------------------------------------------------------------------
'  第1引数:プロシージャ種類(数値)
'  第2引数:コード
'-----------------------------------------------------------------------------
'  戻り値 :プロシージャ種類(文字列)
'******************************************************************************
Function fncGetProcKindName(getKind As Long, getCode As String) As String
    
    Select Case getKind
        Case 0
            '0の場合はSubとFunctionを判断
            Select Case True
            Case Trim(getCode) Like "*Sub *"
                fncGetProcKindName = "Sub"
            Case Trim(getCode) Like "*Function *"
                fncGetProcKindName = "Function"
            End Select
        Case 1
            fncGetProcKindName = "Property Let"
        Case 2
            fncGetProcKindName = "Property Set"
        Case 3
            fncGetProcKindName = "Property Get"
        Case Else
            fncGetProcKindName = "(Unknown)"
    End Select

End Function

'******************************************************************************
' スコープを取得
'-----------------------------------------------------------------------------
'  第1引数:コード
'-----------------------------------------------------------------------------
'  戻り値 :スコープ(文字列)
'******************************************************************************
Function fncGetScope(getCode As String) As String
    Select Case True
        Case Trim(getCode) Like "Private *"
            fncGetScope = "Private"
        Case Trim(getCode) Like "Friend *"
            fncGetScope = "Friend"
        Case Else
            fncGetScope = "Public"
    End Select
End Function

'******************************************************************************
' プロシージャ or プロパティ定義行かを判断
'-----------------------------------------------------------------------------
'  第1引数:コード
'  第2引数:プロシージャ名
'-----------------------------------------------------------------------------
'  戻り値 :判断結果(True:定義行  False:定義行以外)
'******************************************************************************
Function fncChkProcLine(getCode As String, getProcName As String) As Boolean
    
    getCode = " " & Trim(getCode)
    Select Case True
        Case _
        getCode Like "* Sub " & getProcName & "(*", _
        getCode Like "* Function " & getProcName & "(*", _
        getCode Like "* Property * " & getProcName & "(*"
            fncChkProcLine = True
        Case Else
            fncChkProcLine = False
    End Select

End Function


'******************************************************************************
' 行連結文字( _)を結合した文字列を取得
'-----------------------------------------------------------------------------
'  第1引数:コード行数 ※結合した場合、結合後の行数を返す。
'  第2引数:モジュールオブジェクト
'-----------------------------------------------------------------------------
'  戻り値 :編集後のコード
'******************************************************************************
Function fncShpProcCode(ByRef getLine As Long, getObjModule As Object) As String
    
    Dim sTempCode As String
    Do
        sTempCode = Trim(getObjModule.lines(getLine, 1))
        'If Right(getObjModule.Lines(getLine, 1), 2) = " _" Then
        If Right(sTempCode, 2) = " _" Then
            sTempCode = Left(sTempCode, Len(sTempCode) - 1)
                        
            '(の直前で行連結された場合はスペースを詰める
            If Left(sTempCode, 1) = "(" Then
                fncShpProcCode = RTrim(fncShpProcCode)
            End If
            
            fncShpProcCode = fncShpProcCode & sTempCode
            '末尾が行連結文字なら次の行を参照させるため、カウントをアップする
            getLine = getLine + 1
        Else
            '末尾が行連結文字でなければループを抜ける
            fncShpProcCode = fncShpProcCode & sTempCode
            Exit Do
        End If
    Loop

End Function

 ■実行結果