目次
クラスモジュールDebugLogOnAccdbでAccess VBAのデバッグログを取りデバッグを劇的に効率化しよう
皆さんはAccess VBAコードのデバッグに苦労していませんか。
特にAccess内でフォーム、コントロールの動作を記述するイベントプロシージャではその生成時に同様のプロシージャ―名が多数生成されるため
いったい自分がどのイベントプロシージャのデバッグをしているのかがわからなくなったり、別フォームのイベントプロシージャを誤って修正してしまったりということはないでしょうか。
この記事では、このような悩みを解消するため、Accessのプロジェクト内にクラスモジュールDebugLogOnAccdbを定義し
イベントプロシージャ、あるいはそれ以外の一般的なプロシージャ、関数(Function)でこのDebugLogOnAccdb のメソッド .SaveFormLog、.SaveLog を呼び出すことで、デバッグログを簡単に収集し、プロシージャ、イベントをトレースすることでデバッグを劇的に効率化する方法を紹介します。
具体的にはVBE内のメニューの
挿入(I) > クラスモジュール(C)
でクラスモジュール(C)内にDebugLogOnAccdbというクラスモジュールを登録し
標準モジュールの先頭でこのクラスモジュールを使ったパブリック型の DebugLog オブジェクトをインスタンス化し
Public DebugLog As New DebugLogOnAccdb
フォームモジュール内のイベントプロシージャ内で
DebugLog.SaveFormLog "Form_Open"
:
DebugLog.SaveFormLog "Form_Open", Err.Description
と記述したり
標準モジュール、フォームモジュールに内の一般的なプロシージャや関数(Funcrion)内で
DebugLog.SaveLog "Procedure_Name"
:
DebugLog.SaveLog "Procedure_Name", Err.Description
と記述したりすることで
以下のようなタイムスタンプ付きの実行ログを
- イミディエットウインドウ内に表示
- このAccessプロジェクト名に対し一意に決めれれたログファイル内に保存
することができます。
そしてこのログによりプログラムの実行状況が可視化されるため、デバッグを劇的に効率化することができるようになります。
2023/09/10 23:51:17 SampleDB.accdb : Sample : 起動されました。
2023/09/10 23:58:57 SampleDB.accdb : frm002 : Form_Open : Something good
2023/09/11 00:06:19 SampleDB.accdb : frm002 : Form_Open : 起動されました。
2023/09/11 00:06:19 SampleDB.accdb : frm002 : Form_Open : Something good
2023/09/11 00:06:22 SampleDB.accdb : frm001 : Form_Open : 起動されました。
この情報が読者の皆様のお役に立てることを願っています。
解決できること
あなたの Access VBA プロジェクトにこの DebugLogOnAccdbクラスモジュールを定義し
このクラスモジュールを標準モジュール等でDebugLogオブジェクトとしてインスタンス化したのち
あなたが開発中の標準モジュール、フォームモジュールのプロシージャや関数(Funcrion)中に
- DebugLog.SaveLog “プロシージャ名“[,”追加情報”]
- DebugLog.SaveFormLog, “プロシージャ名“[,”追加情報”]
といったメソッドを追記しておくと
デバッグ中あるいはデバッグ後にどのプロシージャ、関数(Function)オブジェクトが起動されたか、例外処理が走っていないか等をログから簡単に確認することが出来ます。
またプロシージャ内へのVBAコーディングの際にはインテリセンス機能により、このオブジェクトで利用可能なプロパティ名、メソッド名を表示できます。
このログの出力有無は クラスモジュール DebugLogOnAccdb中に定義されたDEBUG_MODE というBoolean型の定数の設定値により制御します。
また、このログを最大何行まで保存可能とするかをMAX_LOG_LINESというInteger型の定数の設定値により指定します。
この保存行の上限設定はこのプロジェクトのデバッグ終了後に
DEBUG_MODE =False
への設定をし忘れたようなケースで、ログ容量増大によりシステム破壊等が起きないようにするためのものです。
定数名 | 設定値 | 意味 |
---|---|---|
DEBUG_MODE | プロジェクトの実行モード、ログの出力有無を決めるオブジェクトクラス内定数。 | |
True | デバッグ中モードでログ出力あり | |
False | 通常運用中モードでログ出力無し | |
MAX_LOG_LINES |
ログの最大保存数。 デバッグモードで、無用なログ増大によるシステム障害等を回避するため 直近から最大MAX_LOG_LINESで定義された行数になるまで保存されます。また過去のMAX_LOG_LINESを超える過去部分は自動的に削除します。 |
読んでほしい方
フォームを含む Access VBAのデバッグに苦労されている方、
イベントプロシージャ、通常プロシージャにまたがったタイムスタンプ付きログ収集の仕組みを検討されている方、
には必見の内容です。
クラスモジュールについて
クラスモジュールはVBAでオブジェクト志向型プログラムを行うため
クラス(オブジェクトの設計図)実装を行うためのモジュールで
VBE内のメニューの
挿入(I) > クラスモジュール(C)
でクラスモジュール(C)内にクラス名をつけたモジュールを登録することで定義します。
VBAのクラス実装では一般にこのモジュール中に次のような記述を行います。
種類 | 説明 | |
---|---|---|
プロパティ |
クラス内に保有するデータのこと。 クラスの設計者はこのクラス内で使用するデータを自由に定義します。 一般にクラス内に定義されたデータは外部からは参照しませんが Property ステートメントを使った
という仕組みを利用し、外部から参照したり、値を変更したりすることを許すこともできます。 |
|
Getterプロパティ |
外部から参照可能なデータのプロパティです。 |
|
Setterプロパティ |
外部から設定可能なデータのプロパティです。 |
|
メソッド |
ユーザーに対してこのクラスが提供する機能をプロシージャ、Funcrion(関数)の形で定義します。 またこのプロシージャの中には
という予約定義された特別なプロシージャも定義出来ます。 |
|
Class_Initialize() | クラスの初期化を行うプロシージャです。 このメソッドは以下のようにこのクラスを使ったオブジェクトがインスタンス化されたとき起動されます。 Public DebugLog As New DebugLog |
|
Class_Terminate() | クラスの終了処理を行うプロシージャです。 このメソッドは以下のようにインスタンス化されたオブジェクトが廃棄されたとき起動されます。 Set DebugLog = Nothing |
DebugLogOnAccdbクラスモジュール の概要
プロパティ
このDebugLogOnAccdbクラスモジュールは、Accessのフォーム配下のイベントプロシージャやその他の通常プロシージャで、タイムスタンプ付のログを保存するための仕組みを提供するためのもので
以下のようなプロパティ、メソッドを定義しています。
プロパティ名 | 型 | 意味 | |
---|---|---|---|
FilePath | String |
ログの格納されるファイルの絶対パスを格納しています。 この絶対パスはイミディエットウインドウ中で |
|
IsDebugMode |
Boolean |
このDebugLogクラスモジュールの実行モードを格納しています。 この値の変更はデバッグ、あるいは運用開始時にこのクラスモジュールの先頭にあるDEBUG_MODE 定数を修正することで行います。 この数はイミディエットウインドウ中で |
|
Yes |
デバッグモード中です。 MAX_LOG_LINES で指定された最大行数まで直近のログの保存を行い、最大行を超える過去ログは古いものから順に削除されます。 |
||
No |
デバッグモード中ではありません(=通常運用モードです)。 通常運用モードとしてログの保存は行いません。 |
メソッド
メソッド名 | パラメータ名 | 型 | 省略可否 | 意味 |
---|---|---|---|---|
SaveFormLog | フォーム内のイベントプロシージャ内で タイムスタンプ付きのログを保存するメソッドです。 ログ中あるいはイミディエットウインドウ内に自動的にフォーム名が挿入されます。 |
|||
proc_name | String | 不可 | ログに記録したいプロシージャ名を指定します。 | |
error_message | String | 可 | ログ中に追記したいErr.Description等の文字列を指定します。
この指定が省略された場合には「起動されました。」という文字列が自動挿入されます。 これはイベントプロシージャの先頭でそのプロシージャが起動されたことを記録する場合に使用します。 |
|
SaveLog | フォーム内以外の一般プロシージャ、関数の内でタイムスタンプ付きのログを保存するメソッドです。
ログ中あるいはイミディエットウインドウ内にフォーム名は挿入されません。 |
|||
proc_name | String | 不可 | ログに記録したいプロシージャ名、関数名を指定します。 | |
error_message | String | 可 |
ログ中に追記したいErr.Description等の文字列を指定します。 この指定が省略された場合には「起動されました。」という文字列が自動挿入されます。 これはプロシージャや関数の先頭でそのプロシージャ、関数が起動されたことを記録する場合に使用します。 |
|
ShowLog | なし | ー | ー |
デバッグモードのとき 直近で記録されたログMAX_LOG_LINES行をイミディエットウインドウ内に表示します。 |
DebugLogOnAccdbクラスモジュール の使い方
標準モジュール内でのオブジェクトのインスタンス化
VBAコードの標準モジュールの先頭で以下のように Public な DebugLog オブジェクトをインスタンス化します。
クラスはこのようにインスタンス化(実体化)して初めてオブジェクトとして利用可能になります。
Public DebugLog As New DebugLogOnAccdb
フォームのイベントプロシージャ内での使用例
ログを記録したいプロシージャの中で以下のようなログ保存のメソッド
DebugLog.SaveFormLog
を プロシージャ名を表す文字列、そして必要に応じた追加情報の文字列をパラメータとして呼び出します。
Private Sub Form_Open(Cancel As Integer)
DebugLog.SaveFormLog "Form_Open"
Call StandardizeTextboxes(Me)
On Error GoTo Err_Form_Open
' ここに個別処理を記述
Exit_Form_Open:
Exit Sub
Err_Form_Open:
DebugLog.SaveFormLog "Form_Open", Err.Description
Resume Exit_Form_Open
End Sub
2行目の
Call StandardizeTextboxes(Me)
は以下の参照記事でご紹介しているプロシージャで
フォーム内のテキスト、ラベル等の書式をあわせるプロシージャです。
イベントプロシージャ内に限らず
プロシージャを実装する際には、その起動時間の記録、例外発生原因の記録を含めた以下のような標準的なテンプレートを利用すると
プロシージャの実行ログ、例外処理が発生した場合の原因確認が簡単にできるので、おすすめです。
Private Sub Form_Open(Cancel As Integer)
DebugLog.SaveFormLog "Form_Open"
On Error GoTo Err_Form_Open
' ここに個別処理を記述
Exit_Form_Open:
Exit Sub
Err_Form_Open:
DebugLog.SaveFormLog "Form_Open", Err.Description
Resume Exit_Form_Open
End Sub
行 | VBAコード | 説明 |
---|---|---|
1 | Private Sub Form_Open (Cancel As Integer) |
プロシージャ名 “Form_Open” の開始 |
2 | DebugLog.SaveFormLog “Form_Open” |
でこのプロシージャが開始したことをタイムスタンプ付きでログに取ります。 |
3 | On Error GoTo Err_Form_Open | 例外発生時のジャンプ先を Err_プロシージャ名 という形で定義します。 |
5-6 | Exit_Form_Open: Exit Sub |
このプロシージャの出口となるジャンプ先を Exit_プロシージャ名 という形で定義します。 |
7-9 | Err_Form_Open: DebugLog.SaveFormLog “Form_Open”, Err.Description Resume Exit_Form_Open |
例外処理の開始アドレスを Err_プロシージャ名: という形で定義します。 そしてその原因記述Err.Description を含めた例外発生原因をタイムスタンプ付きでログに取り Exit_Form_Open へ戻ります。 |
10 | End Sub | プロシージャ名 “Form_Open” の終了 |
フォーム以外の一般的なプロシージャ、関数内での使用例
ログを記録したい一般的なプロシージャ、関数内で以下のようなログ保存のメソッド
DebugLog.SaveLog
を プロシージャ名を表す文字列、そして必要に応じた追加情報の文字列をパラメータとして呼び出します。
Sub Sample()
DebugLog.SaveLog "Sample"
On Error GoTo Err_Sample
' ここに個別処理を記述
Exit_Sample:
Exit Sub
Err_Sample:
DebugLog.SaveLog "Sample", Err.Description
Resume Exit_Sample
End Sub
これはフォーム名が表示されないだけで、その他については 先ほどの
DebugLog.SaveFormLog
とほぼ同様です。
何故フォームプロシージャとそれ以外の一般プロシージャで同じ機能を持ったメソッドがわかれているかというと
- 一般プロシージャにはフォームプロシージャが備えているCodeContextObject.Name というプロパティが存在しない
- VBA自身に現在実行中のモジュール名を知る手段が提供されていない
ためです。
ログデータの表示方法
このVBAコードを含むツール(例えばSampleDB.accdb)中のVBEイミディエットウインドウ内で DebugLog.Show メソッドを実行すると
DebugLog.Show
2023/09/10 23:51:17 SampleDB.accdb : Sample : 起動されました。
2023/09/10 23:58:57 SampleDB.accdb : frm002 : Form_Open : Something good
2023/09/11 00:06:19 SampleDB.accdb : frm002 : Form_Open : 起動されました。
2023/09/11 00:06:19 SampleDB.accdb : frm002 : Form_Open : Something good
2023/09/11 00:06:22 SampleDB.accdb : frm001 : Form_Open : 起動されました。
というように保存されたログファイルを簡単に参照できます。
このログは分離用の “:” を除くと以下のようになっています。
- 起動された日付
- 起動された時間
- プロジェクト名(つまりAccessのファイル名)
- フォーム名(フォームから起動された場合のみ)
- プロセス名
- 備考情報(起動、Error.Description等、コード中で設定した文字列)
ログファイルの絶対パス、デバッグモードの表示方法
必要に応じてこのVBAコードを含むツール(例えばSampleDB.accdb)中のVBEイミディエットウインドウ内で 以下のコマンドを実行すると
? DebugLog.FilePath
C:\Users\devel\Tools_Data_Logs\accdb\Sampledb.log
? DebugLog.IsDebugMode
True
というように簡単にログファイルの絶対パス、デバッグモードの表示ができます。
VBAコード
DebugLogOnAccdbクラスモジュール
この DebugLogOnAccdbクラスは、Access VBAを用いたフォームの開発等に応じてその実行ログ、エラーログを簡単にトレース可能とするためのクラスで
VBAのクラスモジュール(C)に DebugLogOnAccdbという名前のクラスモジュールを定義し、標準モジュール内でこれをオブジェクトとしてインスタンス化することで、他の標準モジュール、フォームモジュールからの参照が可能となります。
以下このDebugLogOnAccdbクラスオブジェクトについて簡単にご紹介します。
プロパティ定義
まず、クラスモジュールの先頭に、このクラス内で利用するPrivate変数、Private定数を定義しています。
Option Compare Database
' ログファイルのパスを格納する変数
Private logFilePath As String
' ログファイルの最大行数
Private Const MAX_LOG_LINES As Integer = 50
' デバッグモードの有効/無効を切り替えるフラグ
Private Const DEBUG_MODE As Boolean = True
' ログのファイルパスのGetterプロパティ
Property Get FilePath() As String
FilePath = logFilePath
End Property
' デバッグモードのGetterプロパティ
Property Get IsDebugMode() As Boolean
IsDebugMode = DEBUG_MODE
End Property
そして外部への参照を可能とするFilePath、IsDebugMode をPropertyステートメントを使ってプロパティとして公開設定しています。
Property ステートメントはクラスモジュールにカスタム プロパティを作成するステートメントで、クラスモジュール内に定義したローカル変数を外部から参照したり、値を設定したいときに使用します。
記述例 | 説明 |
---|---|
Property Get FilePath() As String FilePath = logFilePath End Property |
プロパティ FilePathに読み取り可能なパーミッションを設定します。
イミディエットウインドウ中で |
Property Let FilePath(ByVal file_path As String) logFilePath = file_path End Property |
プロパティ FilePathに書きこみ可能なパーミッションを設定します。
運用上の不要なので本記事では使用していませんが、イミディエットウインドウ中で |
この Property ステートメントには他にオブジェクトに対しての値設定を行う
Property Set というステートメントもありますが、これらを含む詳細な情報に関しては Excelの神髄 (@yamaoka_ss)さんのサイト
・第140回.Property {Get|Let|Set} ステートメント
に良質な情報が掲載されていますので、必要に応じてそちらもご確認ください。
Class_Initialize
Class_Initialize というVBAで予約されたプロシージャ名は、インスタンス化されたオブジェクトの初期設定処理を行います。
' クラスの初期化
Private Sub Class_Initialize()
' ファイルシステムオブジェクトの生成
Dim fsObject As Object
Set fsObject = CreateObject("Scripting.FileSystemObject")
' ユーザーのプロファイルディレクトリにログディレクトリを作成
logFilePath = Environ("UserProfile") & "\Tools_Data_Logs"
If Not fsObject.FolderExists(logFilePath) Then
MkDir (logFilePath)
End If
' ログディレクトリ内に.accdbディレクトリを作成
logFilePath = logFilePath & "\accdb"
If Not fsObject.FolderExists(logFilePath) Then
MkDir (logFilePath)
End If
Set fsObject = Nothing
' ログファイルのパスを設定
logFilePath = Environ("UserProfile") & "\Tools_Data_Logs\accdb\" & Replace(CurrentProject.Name, ".accdb", ".log")
End Sub
ここではインスタンス化されたオブジェクト内に定義された
logFilePath
という内部変数に、環境変数 %USERPROFILE% を起点としたこのAccessプロジェクトのログ保存フォルダの絶対パス
%USERPROFILE%\Tools_Data_Logs\accdb\実行中のプロジェクト名.log
を設定しています。
こうしたツールのフォルダ環境については必要に応じて以下の記事も参照ください。
Class_Terminate
Class_TerminateというVBAで予約されたプロシージャ名は、インスタンス化されたオブジェクトの終了処理を行います。
' クラスの終了処理
Private Sub Class_Terminate()
' ファイルシステムオブジェクトの生成
Dim fsObject As Object
Set fsObject = CreateObject("Scripting.FileSystemObject")
' ログファイルが存在する場合、削除
If fsObject.FileExists(logFilePath) = True Then
fsObject.DeleteFile filespec:=logFilePath, force:=True
Debug.Print logFilePath & " が削除されました。"
End If
End Sub
ログというファイルの性質から、運用時にこのメソッドを使用する局面はないと思われますが、もし収集されたログを全て削除したい場合はVBEのイミディエットウインドウ内で以下のコマンドを入力すると、このプロジェクトファイルのログが削除されます。
Set DebugLog = Nothing
C:\Users\devel\Tools_Data_Logs\accdb\Access開発_実践ノウハウ.log が削除されました。
TruncateLog
次の SaveFormLog、SaveLog から呼び出されるプロシージャで ログファイルの保存行数が MAX_LOG_LINES を超えているとき、古いものから順に削除するプロシージャです。
' ログファイルの行数を制限するサブルーチン
Private Sub TruncateLog()
' ログファイルの内容を一時的に保持する配列
Dim logBuffer() As String
Dim logLineCounter As Integer
Dim line As String
' ファイルシステムオブジェクトの生成
Dim fsObject As Object
Set fsObject = CreateObject("Scripting.FileSystemObject")
' ログファイルが存在する場合
If fsObject.FileExists(logFilePath) = True Then
Dim fileNo As Integer
fileNo = FreeFile
' ログファイルを読み込み、行数を数える
Open logFilePath For Input As #fileNo
logLineCounter = 0
Do Until EOF(1)
Line Input #fileNo, line
If (Len(line) <> 0) Then
logLineCounter = logLineCounter + 1
End If
Loop
Close #fileNo
' ログバッファの初期化
ReDim logBuffer(logLineCounter)
' ログファイルを再度読み込み、ログバッファに格納
Open logFilePath For Input As #fileNo
logLineCounter = 0
Do Until EOF(1)
Line Input #fileNo, line
If Len(line) <> 0 Then
logBuffer(logLineCounter) = line
logLineCounter = logLineCounter + 1
End If
Loop
Close #fileNo
' ログファイルが最大行数を超える場合、古いログを削除して新しいログを保存
If logLineCounter > MAX_LOG_LINES Then
fsObject.DeleteFile filespec:=logFilePath, force:=True
fileNo = FreeFile
' ログファイルを追記モードで開き、最新のログだけを保存
Open logFilePath For Append As #fileNo
Dim index As Integer
For index = logLineCounter - MAX_LOG_LINES To logLineCounter
Print #fileNo, logBuffer(index)
Next index
Close #fileNo
End If
End If
End Sub
SaveFormLog
フォーム内のイベントプロシージャから呼ばれることを前提としたメソッドの実装プロシージャで、第二パラメータerror_message が省略された場合には
error_message = “起動されました。”
を補完した上で
整形されたタイムスタンプ、CurrentProject.Name から得られるウロジェクト名、CodeContextObject.Nameから得られるフォーム名、proc_nameで指定されたプロシージャ名、error_messageで指定されたメッセージを
イミディエットウインドウに表示し
ログファイルに保存し
そしてログの行数を制限します。
' フォームのログを保存するサブルーチン
Sub SaveFormLog(proc_name As String, Optional error_message As String)
' エラーメッセージが指定されていない場合、"起動されました。"を使用
If error_message = "" Then
error_message = "起動されました。"
End If
' デバッグモードが有効な場合のみログを出力
If debug_mode = True Then
' デバッグウィンドウにログを出力
Debug.Print Format(Now(), "yyyy/mm/dd hh:nn:ss") & " " & CurrentProject.Name & " : " & CodeContextObject.Name & " : " & proc_name & " : " & error_message
Dim fileNo As Integer ' ファイル番号
fileNo = FreeFile
' ログファイルを追記モードで開き、ログを保存
Open logFilePath For Append As #fileNo
Print #fileNo, Format(Now(), "yyyy/mm/dd hh:nn:ss") & " " & CurrentProject.Name & " : " & CodeContextObject.Name & " : " & proc_name & " : " & error_message
Close #fileNo
' ログの行数を制限
Call TruncateLog
End If
End Sub
SaveLog
フォーム内以外の一般的なイベントプロシージャ、関数から呼ばれることを前提としたメソッドの実装プロシージャで、第二パラメータerror_message が省略された場合には
error_message = “起動されました。”
を補完した上で
整形されたタイムスタンプ、CurrentProject.Name から得られるプロジェクト名、proc_nameで指定されたプロシージャ名、error_messageで指定されたメッセージを
イミディエットウインドウに表示し
ログファイルに保存し
そしてログの行数を制限します。
' プロシージャ・関数のログを保存するサブルーチン
Sub SaveLog(proc_name As String, Optional error_message As String)
' エラーメッセージが指定されていない場合、"起動されました。"を使用
If error_message = "" Then
error_message = "起動されました。"
End If
' デバッグモードが有効な場合のみログを出力
If debug_mode = True Then
' デバッグウィンドウにログを出力
Debug.Print Format(Now(), "yyyy/mm/dd hh:nn:ss") & " " & CurrentProject.Name & " : " & proc_name & " : " & error_message
Dim fileNo As Integer ' ファイル番号
fileNo = FreeFile
' ログファイルを追記モードで開き、ログを保存
Open logFilePath For Append As #fileNo
Print #fileNo, Format(Now(), "yyyy/mm/dd hh:nn:ss") & " " & CurrentProject.Name & " : " & proc_name & " : " & error_message
Close #fileNo
' ログの行数を制限
Call TruncateLog
End If
End Sub
ShowLog
ログ表示を行うメソッドの実装プロシージャで、logFilePath に設定されているログファイルの絶対パスをもとにログファイルの内容をイミディエットウインドウに出力します。
' ログを表示するサブルーチン
Sub ShowLog()
' ファイルシステムオブジェクトの生成
Dim fsObject As Object
Set fsObject = CreateObject("Scripting.FileSystemObject")
Dim logLine As String
' デバッグモードが有効な場合のみログを表示
If DEBUG_MODE = True Then
' ログファイルが存在する場合
If fsObject.FileExists(logFilePath) = True Then
Dim fileNo As Integer
fileNo = FreeFile
' ログファイルを読み込み、内容をデバッグウィンドウに表示
Open logFilePath For Input As #fileNo
Do Until EOF(1)
Line Input #fileNo, logLine
Debug.Print logLine
Loop
Close #fileNo
End If
End If
End Sub
まとめ
この記事では、Access内でフォーム、コントロールの動作を記述する多数のイベントプロシージャに対するデバッグを行う中で
- いったい自分がどのイベントプロシージャのデバッグをしているのかがわからなくなった経験がある
- 別フォームのイベントプロシージャを誤って修正してしまったことがある
といった悩みを解消するため
Accessのプロジェクト内にクラスモジュールDebugLogOnAccdbを定義し、標準モジュール内でこれを DebugLog というオブジェクトとしてインスタンス化したあと
イベントプロシージャ、あるいはそれ以外の一般的なプロシージャ、関数(Function)でこのDebugLog のメソッド DebugLog.SaveFormLog、DebugLog.SaveLog を呼び出すことで
デバッグログを簡単に収集し、プロシージャ、イベントをトレースすることで、デバッグを劇的に効率化する方法を紹介しました。
この情報が読者の皆様のお役に立てることを願っています。
こんにちは。 しらかば堂です。
皆さんの VBA による Access フォームの開発はかどってますか?