ExcelVBAのメソッドにログを簡単に追加する方法
ExcelVBAでログにより、解析を行いたいときがあるが、既存のExcelファイルではログが付与されていないことが多い。また、ExcelVBAではメソッド名の取得が出来ないため、メソッド名をログ出力する場合は、文字を手入力してログ出力しなければならない。(※調査したが、リフレクションの機能が弱いため動的に取得することは不可能なようだった。)
そのため、以下の手順により対応することとする。
①ExcelVBAのコードをVBAコードにより全エクスポート
②コンソールログ出力用の関数をModuleに用意
③VSCodeにより文字列を置換する
④ExcelVBAのコードで既に存在するクラス等を一括開放(削除)
⑤③で置換したものをExcelVBAに一括で取り込む
この手順では、手で関数名の入力が必要な作業をVSCodeの置換によりログ出力コードを自動生成するといったものである。
手順詳細は以下を参照。
手順詳細
前提条件
あらかじめ以下のソースコードを取り込んでおくこと※①②④⑤が実行可能となる。
手順 ①ExcelVBAのコードをVBAコードにより全エクスポート
(1)開発タブ > マクロ > VBAソースコード一括出力 > 実行をクリック
(2)出力先のフォルダを選択してOKをクリック。
OKをクリック後は指定したフォルダにファイルが出力される
手順 ②コンソールログ出力用の関数をModuleに用意
前提条件の作業により以下のコードが取り込まれていることを確認すること
' ログ出力
Sub LogInfo(ByRef classInstance As Object, ByVal str As String)
Dim moduleName As String
moduleName = TypeName(classInstance)
Debug.Print moduleName & "." & str
End Sub
この関数の使い方は以下のように使うが、このままだと関数名の箇所が手入力となってしまうがソースコードはこのままとする。
Call LogInfo(Me , "関数名")
手順 ③VSCodeにより文字列を置換する
①で出力したソースコードをVSCodeを用いて文字列置換によりコードにログを一括で埋め込みを行う。※ポイント
コード変換前から変換後のイメージは以下の通り。
変換前コード
Public Function Method1() As String
xxxx
yyyy
End Function
変換後コード
Public Function Method1() As String
Call LogInfo(Me, "Method1")
xxxx
yyyy
End Function
変換後コードにはCall LogInfo(Me, “Method1”)を埋め込むように置換するといったものである。
手順詳細は以下の通り。
(1)VSCodeで対象のプロジェクトを開く > Ctrl + Shift + F > 赤丸の正規表現を有効にする
(2)1回目の置換は以下の条件で行う。
検索パターン:(Public|Private) (Function|Sub) (\w+)\s*\(([^)]*)\)(\s*As\s*[^\n]+)?
置換パターン:$1 $2 $3($4)$5\n Call LogInfo(Me, "$3")$5
(3)2回目の置換は以下の条件で行う。
検索パターン:Call LogInfo\(Me, "(\w+)"\)\s*As\s+\w+
置換パターン:Call LogInfo(Me, "$1")
これにより、置換により全ソースコードにLogInfoが追加される。
※あくまでもVBA置換の為、実行する前にバックアップは必ず取っておくこと。
手順 ④ExcelVBAのコードで既に存在するクラス等を一括開放(削除)
取り込みを行う前に既存のものを削除しておく必要がある。削除しないと取り込んだときに連番の名前となってしまう。
VBAではクラスモジュール等を一括削除することが画面操作からできない為、前提条件で取り込んでおいたマクロを使う。
(1)開発タブ > マクロ > VBAクラスモジュール一括開放 > 実行をクリック
⑤③で置換したものをExcelVBAに一括で取り込む
ExcelVBAを開いてファイルをエクスプローラーで全選択してドラッグアンドドロップすることで一括取り込みが可能。
①でエクスポートした時点で以下のコードが付与して、エクスポートするようにしているため、そのままドラッグアンドドロップすることで正しい位置に取り込むことが可能となる。※以下が付与されていない場合classでなくモジュールの方に取り込まれてしまうため注意
VERSION 1.0 CLASS
BEGIN
MultiUse = -1 'True
End
Attribute VB_Name = " & VBComponent.Name &
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = False
Attribute VB_Exposed = False