【ExcelVBA】モジュール内のプロシージャ名を全て取得するには

この記事では、モジュール内のプロシージャ名を全て取得する方法についてご説明します。

【動画】モジュール内のプロシージャ名を全て取得する実際の動き

本題に入る前に、まずは次の動画をご覧ください。


CodeModuleオブジェクトを使ってシート「Sheet1」のモジュール内にあるプロシージャ名を取得しています。

プロシージャ名は、CodeModuleオブジェクトのProcOfLineメソッドを実行して取得しています。

マクロ作成の流れ

STEP.1
マクロのコードを1行1行参照し、その中にプロシージャが存在していればプロシージャ名を取得する
マクロのコードを1行1行参照し、その中にプロシージャが存在していればプロシージャ名を取得します。

Excelファイルの例

今回は次のExcelファイルを用意しました。

VBEには名称を取得したいプロシージャをいくつか用意しました。

Excelファイル(プロシージャ名を出力するシート)

以下のExcelファイルには、取得したプロシージャ名を出力する表が用意されています。

なお、今回はプロシージャ名だけではなくスコープ(publicやprivateなど)と、プロシージャの種類(subやfunctionなど)も表に出力します。
(出力結果は動作確認の「マクロ実行後」をご覧ください)

ExcelファイルのVBE画面(テスト用にプロシージャを用意)

ExcelファイルのVBE画面には今回テスト用にいくつかプロシージャを用意しています。

以下の画像にあるプロシージャの名称を全て取得します。

コードの例

Excelのマクロのコード(例)

Option Explicit
Public tWs As Worksheet             '今回のサンプル用に用意したworksheet変数(サンプル用であり、ただプロシージャ名を取得するために用意した本題には関係のない変数)

Public Property Let proc1(ByVal val As String)

End Property

Public Property Set proc2(ws As Worksheet)
    Set tWs = ws
End Property

Public Property Get proc3(ByVal val As String)

End Property

Private Property Let proc4(ByVal val As String)

End Property

Private Property Set proc5(ws As Worksheet)
    Set tWs = ws
End Property

Private Property Get proc6(ByVal val As String)

End Property

Friend Property Let proc7(ByVal val As String)

End Property

Friend Property Set proc8(ws As Worksheet)
    Set tWs = ws
End Property

Friend Property Get proc9(ByVal val As String)

End Property

Static Property Let proc10(ByVal val As String)

End Property

Static Property Set proc11(ws As Worksheet)
    Set tWs = ws
End Property

Static Property Get proc12(ByVal val As String)

End Property

Public Sub proc13()

End Sub

Private Sub proc14()

End Sub

Friend Sub proc15()

End Sub

Static Sub proc16()

End Sub

Public Function proc17()

End Function

Private Function proc18()

End Function

Friend Function proc19()

End Function

Static Function proc20()

End Function

Property Let proc21(ByVal val As String)

End Property
    
Property Set proc22(x As UserForm)

End Property

Property Get proc23(ByVal val As String)

End Property

Sub proc24()

End Sub

Function proc25()

End Function


Sub test()
    
    Dim procName        As String           'プロシージャ名用変数
    Dim cnt             As Long             'カウンタ
    Dim procCnt         As Long             'プロシージャの数を数えるためのカウンタ
    Dim obj             As Object           'CodeModuleオブジェクトを格納するオブジェクト変数
    Dim meMdl           As String           '自分自身のモジュール
        
    'プロシージャの数をカウントする用のカウンタを初期化する
    procCnt = 0
    
    'プロシージャ名用変数にはじめは関数名には存在しない適当な文字列を入力しておく(ブランク状態にはしない)
    procName = "dummyStr"
    
    '自分自身のモジュール名を取得する
    meMdl = Application.VBE.ActiveCodePane.CodeModule.Name
        
    '自分自身でVBEを操作するために使うCodeModuleオブジェクトを変数objに代入する
    Set obj = ThisWorkbook.VBProject.VBComponents.Item(meMdl).CodeModule
    
    With obj
    
        '対象モジュールの行数分ループするfor文
        For cnt = 1 To .CountOfLines
        
            If .ProcOfLine(cnt, 0) <> "" Then
            
                'プロシージャが取得されている場合
            
                '現在参照しているプロシージャ名とすでに取得していたプロシージャ名を比較
                If procName <> .ProcOfLine(cnt, 0) Then
                
                    'すでに取得したプロシージャ名と、マクロが参照するプロシージャ名が違う場合
                    '→(マクロが新たに次のプロシージャを参照する場合)
                    
                    '(新たな次の)プロシージャ名を取得する
                    procName = .ProcOfLine(cnt, 0)
                    
                    procCnt = procCnt + 1
                    
                End If
                
            End If
                
            If InStr(.Lines(cnt, 1), procName) > 0 Then
            
                'プロシージャ名が含まれているソースコード場合
                
                'スコープの取得
                If InStr(LCase(.Lines(cnt, 1)), "public ") > 0 Then
                
                    'プロシージャ名が含まれているソースコードに「public 」が含まれている場合
                
                    'A列のセルに「public」を出力する
                    Worksheets("work").Range("A" & procCnt + 1).Value = "public"
                    
                ElseIf InStr(LCase(.Lines(cnt, 1)), "private ") > 0 Then
                
                    'プロシージャ名が含まれているソースコードに「private 」が含まれている場合
                
                    'A列のセルに「private」を出力する
                    Worksheets("work").Range("A" & procCnt + 1).Value = "private"
                
                ElseIf InStr(LCase(.Lines(cnt, 1)), "friend ") > 0 Then
                
                    'プロシージャ名が含まれているソースコードに「Friend 」が含まれている場合
                
                    'A列のセルに「sub」を出力する
                    Worksheets("work").Range("A" & procCnt + 1).Value = "Friend"
                
                ElseIf InStr(LCase(.Lines(cnt, 1)), "static ") > 0 Then
                
                    'プロシージャ名が含まれているソースコードに「Static 」が含まれている場合
                
                    'A列のセルに「sub」を出力する
                    Worksheets("work").Range("A" & procCnt + 1).Value = "Static"
                
                End If
                
                '種類の取得
                If InStr(LCase(.Lines(cnt, 1)), "sub ") > 0 Then
                
                    'プロシージャ名が含まれているソースコードに「sub 」が含まれている場合
                
                    'B列のセルに「sub」を出力する
                    Worksheets("work").Range("B" & procCnt + 1).Value = "sub"
                    
                ElseIf InStr(LCase(.Lines(cnt, 1)), "function ") > 0 Then
                
                    'プロシージャ名が含まれているソースコードに「function 」が含まれている場合
                
                    'B列のセルに「function」を出力する
                    Worksheets("work").Range("B" & procCnt + 1).Value = "function"
                
                ElseIf InStr(LCase(.Lines(cnt, 1)), "property let ") > 0 Then
                
                    'プロシージャ名が含まれているソースコードに「property let 」が含まれている場合
                
                    'B列のセルに「Property Let」を出力する
                    Worksheets("work").Range("B" & procCnt + 1).Value = "Property Let"
                
                ElseIf InStr(LCase(.Lines(cnt, 1)), "property set ") > 0 Then
                
                    'プロシージャ名が含まれているソースコードに「property set 」が含まれている場合
                
                    'B列のセルに「Property Set」を出力する
                    Worksheets("work").Range("B" & procCnt + 1).Value = "Property Set"
                    
                ElseIf InStr(LCase(.Lines(cnt, 1)), "property get ") > 0 Then
                
                    'プロシージャ名が含まれているソースコードに「property get 」が含まれている場合
                
                    'B列のセルに「Property Get」を出力する
                    Worksheets("work").Range("B" & procCnt + 1).Value = "Property Get"
                
                End If
                
                'C列のセルにプロシージャ名を出力する
                Worksheets("work").Range("C" & procCnt + 1).Value = procName
            
            End If
            
        Next cnt
      
    End With
    
    '後処理
    Set obj = Nothing
    
End Sub

注目すべきコード①

最初に見て頂きたいのは4行目から102行目です。

Public Property Let proc1(ByVal val As String)

End Property

Public Property Set proc2(ws As Worksheet)
    Set tWs = ws
End Property

Public Property Get proc3(ByVal val As String)

End Property

Private Property Let proc4(ByVal val As String)

End Property

Private Property Set proc5(ws As Worksheet)
    Set tWs = ws
End Property

Private Property Get proc6(ByVal val As String)

End Property

Friend Property Let proc7(ByVal val As String)

End Property

Friend Property Set proc8(ws As Worksheet)
    Set tWs = ws
End Property

Friend Property Get proc9(ByVal val As String)

End Property

Static Property Let proc10(ByVal val As String)

End Property

Static Property Set proc11(ws As Worksheet)
    Set tWs = ws
End Property

Static Property Get proc12(ByVal val As String)

End Property

Public Sub proc13()

End Sub

Private Sub proc14()

End Sub

Friend Sub proc15()

End Sub

Static Sub proc16()

End Sub

Public Function proc17()

End Function

Private Function proc18()

End Function

Friend Function proc19()

End Function

Static Function proc20()

End Function

Property Let proc21(ByVal val As String)

End Property
    
Property Set proc22(x As UserForm)

End Property

Property Get proc23(ByVal val As String)

End Property

Sub proc24()

End Sub

Function proc25()

End Function

以上のコードは、プロシージャ名を取得するために用意したテスト用プロシージャです。

このプロシージャは今回のサンプルとして用意した「プロシージャ名を取得するため」だけに用意したプロシージャであり、何か実行するプロシージャではありません。

今回のサンプルの目的はこのプロシージャの名称を取得するのが目的なので、以上のコードはただコード内に用意された何もしないプロシージャになります。

注目すべきコード②

次に見て頂きたいのは120行目から123行目です。

    '自分自身のモジュール名を取得する
    meMdl = Application.VBE.ActiveCodePane.CodeModule.Name
        
    '自分自身でVBEを操作するために使うCodeModuleオブジェクトを変数objに代入する
    Set obj = ThisWorkbook.VBProject.VBComponents.Item(meMdl).CodeModule

以上のコードは、実行しているプロシージャ名を取得するプロシージャ(test)がどのモジュールなのかを取得し、CodeModuleオブジェクトを変数objに代入しているコードになります。

今回のサンプルでは、プロシージャ名を取得するプロシージャ(test)はシート「sheet1」モジュールで実行しているので、120行目で「sheet1」が取得されて変数「meMdl」に格納されます。

123行目では、VBEを操作するために使うCodeModuleオブジェクトを変数objに代入しているコードです。

変数objに代入しなくても構いませんが、「ThisWorkbook.VBProject.VBComponents.Item(meMdl).CodeModule」が長い文字列なので変数objに代入しています。

注目すべきコード③

次に見て頂きたいのは128行目です。

        '対象モジュールの行数分ループするfor文
        For cnt = 1 To .CountOfLines

以上のコードは、対象モジュールの行数分ループするfor文です。

対象モジュールの中にあるプロシージャ名を取得するため、対象モジュールの行数分ループさせます。

対象モジュールの行数はCodeModuleオブジェクトのCountOfLinesプロパティから取得することができます。

注目すべきコード④

次に見て頂きたいのは130行目から147行目です。

            If .ProcOfLine(cnt, 0) <> "" Then
            
                'プロシージャが取得されている場合
            
                '現在参照しているプロシージャ名とすでに取得していたプロシージャ名を比較
                If procName <> .ProcOfLine(cnt, 0) Then
                
                    'すでに取得したプロシージャ名と、マクロが参照するプロシージャ名が違う場合
                    '→(マクロが新たに次のプロシージャを参照する場合)
                    
                    '(新たな次の)プロシージャ名を取得する
                    procName = .ProcOfLine(cnt, 0)
                    
                    procCnt = procCnt + 1
                    
                End If
                
            End If

以上のコードは、プロシージャ名を取得する処理のコードです。

130行目では、ProcOfLineの値がブランクかどうかを判定しています。

ProcOfLineはプロパティはプロシージャ名を返すプロパティで、ProcOfLineプロパティがブランクを返さなければプロシージャ名が取得できていることが分かります。

プロシージャ名が取得できている場合は、135行目で変数procNameに格納されているプロシージャ名と、ProcOfLineで取得していたプロシージャ名を比較します。

変数procNameに格納されているプロシージャ名と、ProcOfLineで取得していたプロシージャ名が異なっていれば、それが新たな別のプロシージャ名なので、141行目でその新たな別のプロシージャ名を変数procNameに格納します。

注目すべきコード⑤

次に見て頂きたいのは149行目です。

            If InStr(.Lines(cnt, 1), procName) > 0 Then

以上のコードは、コードの中にプロシージャ名が含まれているかを判定するIF文のコードです。

この条件に合致した場合に、「注目すべきコード⑥」でお話しますが、プロシージャのスコープ(publicやprivateなど)や種類(subやfunctionなど)を取得していきます。

注目すべきコード⑥

次に見て頂きたいのは154行目から182行目です。

                'スコープの取得
                If InStr(LCase(.Lines(cnt, 1)), "public ") > 0 Then
                
                    'プロシージャ名が含まれているソースコードに「public 」が含まれている場合
                
                    'A列のセルに「public」を出力する
                    Worksheets("work").Range("A" & procCnt + 1).Value = "public"
                    
                ElseIf InStr(LCase(.Lines(cnt, 1)), "private ") > 0 Then
                
                    'プロシージャ名が含まれているソースコードに「private 」が含まれている場合
                
                    'A列のセルに「private」を出力する
                    Worksheets("work").Range("A" & procCnt + 1).Value = "private"
                
                ElseIf InStr(LCase(.Lines(cnt, 1)), "friend ") > 0 Then
                
                    'プロシージャ名が含まれているソースコードに「Friend 」が含まれている場合
                
                    'A列のセルに「sub」を出力する
                    Worksheets("work").Range("A" & procCnt + 1).Value = "Friend"
                
                ElseIf InStr(LCase(.Lines(cnt, 1)), "static ") > 0 Then
                
                    'プロシージャ名が含まれているソースコードに「Static 」が含まれている場合
                
                    'A列のセルに「sub」を出力する
                    Worksheets("work").Range("A" & procCnt + 1).Value = "Static"
                
                End If

以上のコードは、スコープを取得してシートに出力している処理のコードです。

プロシージャ名が含まれているコード内に「public」「private」「friend」「Static」のいずれかのスコープが含まれていれば、そのスコープをA列のセルに出力しています。

注目すべきコード⑦

次に見て頂きたいのは185行目から220行目です。

                '種類の取得
                If InStr(LCase(.Lines(cnt, 1)), "sub ") > 0 Then
                
                    'プロシージャ名が含まれているソースコードに「sub 」が含まれている場合
                
                    'B列のセルに「sub」を出力する
                    Worksheets("work").Range("B" & procCnt + 1).Value = "sub"
                    
                ElseIf InStr(LCase(.Lines(cnt, 1)), "function ") > 0 Then
                
                    'プロシージャ名が含まれているソースコードに「function 」が含まれている場合
                
                    'B列のセルに「function」を出力する
                    Worksheets("work").Range("B" & procCnt + 1).Value = "function"
                
                ElseIf InStr(LCase(.Lines(cnt, 1)), "property let ") > 0 Then
                
                    'プロシージャ名が含まれているソースコードに「property let 」が含まれている場合
                
                    'B列のセルに「Property Let」を出力する
                    Worksheets("work").Range("B" & procCnt + 1).Value = "Property Let"
                
                ElseIf InStr(LCase(.Lines(cnt, 1)), "property set ") > 0 Then
                
                    'プロシージャ名が含まれているソースコードに「property set 」が含まれている場合
                
                    'B列のセルに「Property Set」を出力する
                    Worksheets("work").Range("B" & procCnt + 1).Value = "Property Set"
                    
                ElseIf InStr(LCase(.Lines(cnt, 1)), "property get ") > 0 Then
                
                    'プロシージャ名が含まれているソースコードに「property get 」が含まれている場合
                
                    'B列のセルに「Property Get」を出力する
                    Worksheets("work").Range("B" & procCnt + 1).Value = "Property Get"
                
                End If

以上のコードは、プロシージャの種類を取得してシートに出力している処理のコードです。

プロシージャ名が含まれているコード内に「sub」「function」「Property Let」「Property Set」「Property Get」のいずれかの種類が含まれていれば、その種類をB列のセルに出力しています。

注目すべきコード⑧

次に見て頂きたいのは223行目です。

                'C列のセルにプロシージャ名を出力する
                Worksheets("work").Range("C" & procCnt + 1).Value = procName

以上のコードは、プロシージャ名をシートに出力している処理のコードです。

取得したプロシージャ名が変数「procName」に格納されているので、そのプロシージャ名をC列のセルに出力しています。

動作確認

マクロ実行前

今回は「Excelファイルの例」のexcelファイルを使います。

マクロ実行後

マクロ実行後はスコープと種類、プロシージャ名が出力されました。

最後に

本記事では、モジュール内のプロシージャ名を全て取得する方法についてご説明しました。

作成した全プロシージャ名を確認したい時は本記事を参考にしてみてくださいね。

Excelのスキル向上やExcelの基礎知識をしっかりと学びたいなら

Excelのスキルを習得したい、Excelの基礎知識をもっと理解したい、そう考えているなら「無期限サポート付きExcel講座【すごい改善】」がおすすめです。

Excelのスキルの基礎を身につけるなら【すごい改善】で無期限サポート付きがあるので、これで「Excelのスキルや基礎」を学ぶのにおすすめですよ。

→ 受講後、何度でも無期限でメールで質問できるアフターサポートがついているExcelマスター講座はこちら