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
■実行結果



