この記事では、モジュール内のプロシージャ名を全て取得する方法についてご説明します。
【動画】モジュール内のプロシージャ名を全て取得する実際の動き
本題に入る前に、まずは次の動画をご覧ください。
CodeModuleオブジェクトを使ってシート「Sheet1」のモジュール内にあるプロシージャ名を取得しています。
プロシージャ名は、CodeModuleオブジェクトのProcOfLineメソッドを実行して取得しています。
マクロ作成の流れ
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のスキルや基礎」を学ぶのにおすすめですよ。