web-dev-qa-db-ja.com

MS-Access、VBA、およびエラー処理

これは実際の質問よりも観察です。MS-Access(および一般にVBA)には、エラー処理コードを自動的に生成でき、エラーが発生したときに行番号を表示できるツールが必死に欠けています。解決策を見つけましたか?それは何ですか?数年前にこの基本的な問題に対する正しい答えを見つけてから、何百時間も節約できたことに気づきました。この非常に重要な問題に対するあなたのアイデアと解決策を知りたいと思います。

19

私の解決策は次のとおりです。

  1. install MZ-Tools 、VBA用の非常に興味深いアドオン。いいえ、彼らはこれを書くために私にお金を払っていませんでした。バージョン3は無料でしたが、バージョン8.0以降、アドインは市販されています。
  2. このような標準エラーハンドラコードをプログラムします(MZ-ツールメニュー/オプション/エラーハンドラを参照)。

On Error GoTo {PROCEDURE_NAME}_Error
{PROCEDURE_BODY}
On Error GoTo 0
Exit {PROCEDURE_TYPE}

{PROCEDURE_NAME}_Error:
debug.print "#" & Err.Number, Err.description, "l#" & erl, "{PROCEDURE_NAME}", "{MODULE_NAME}"

この標準エラーコードは、MZ-Toolsメニューの対応するボタンをクリックすることにより、すべてのプロシージャと関数に自動的に追加できます。ここでは、VBA標準ライブラリの非表示で文書化されていない関数「Erl」を参照していることに気付くでしょう。これは「エラーライン」を表します。了解しました! MZ-Toolsにコードの行に自動的に番号を付けるように依頼すると、「Erl」はエラーが発生した行の番号を示します。次のようなエラーの完全な説明がすぐに表示されます。

#91, Object variable or With block variable not set, l# 30, addNewField, Utilities

もちろん、システムの関心に気づいたら、デバッグウィンドウにデータを表示するだけでなく、次のこともできる、より洗練されたエラーハンドラーを考えることができます。

  1. 画面にメッセージとして表示する
  2. エラーの説明を含む行をエラーログファイルに自動的に挿入しますまたは
  3. accessを使用している場合、またはデータベースに接続している場合は、Tbl_Errorテーブルにレコードを自動的に追加します。

つまり、ユーザーレベルで生成された各エラーは、マシンまたはネットワーク上のどこかに、ファイルまたはテーブルのいずれかに保存できます。 自動エラー報告システムの構築 VBAとの連携について話しているのですか?

6

「Erl」を使用すると、エラーの前の最後のラベル(10、20、30など)が表示されますか?

Private Sub mySUB()
On Error GoTo Err_mySUB
10:
    Dim stDocName As String
    Dim stLinkCriteria As String
20:
    stDocName = "MyDoc"
30:
    DoCmd.openform stDocName, acFormDS, , stLinkCriteria    
Exit_mySUB:
    Exit Sub
Err_mySUB:
    MsgBox Err.Number & ": " & Err.Description & " (" & Erl & ")"
    Resume Exit_mySUB
End Sub
7
BIBD

さて、あなたが求めることを行うツールがいくつかあります MZ ToolsFMS Inc 頭に浮かぶ。

基本的に、それらは以下を追加することを含みます:

On Error GoTo ErrorHandler

各procの先頭に、最後に:

ErrorHandler:
  Call MyErrorhandler Err.Number, Err.Description, Err.LineNumber

通常、カスタムエラーメッセージを表示およびログに記録できるグローバルエラーハンドラーの呼び出しでラベルを付けます

5
DJ.

Chip Pearson のように、いつでも自分のツールをロールできます。 VBAは実際にそれ自体にアクセスできますIDE Microsoft Visual Basic for Applications Extensibility 5.3 Library 。私は自分自身での作業を容易にするいくつかのクラスモジュールを作成しました。それらは Code Review SE にあります。

これを使用して、On Error GoTo ErrHandlerステートメントと、エラー処理スキーマに関連する適切なラベルと定数を挿入します。また、定数を実際のプロシージャ名と同期するためにも使用します(関数名が変更された場合)。

2
RubberDuck

DJが言及したツールを購入する必要はありません。これが私の無料のコードです:

Public Sub InsertErrHandling(modName As String)
    Dim Component As Object
    Dim Name As String
    Dim Kind As Long
    Dim FirstLine As Long
    Dim ProcLinesCount As Long
    Dim Declaration As String
    Dim ProcedureType As String
    Dim Index As Long, i As Long
    Dim LastLine As Long
    Dim StartLines As Collection, LastLines As Collection, ProcNames As Collection, ProcedureTypes As Collection
    Dim gotoErr As Boolean

    Kind = 0
    Set StartLines = New Collection
    Set LastLines = New Collection
    Set ProcNames = New Collection
    Set ProcedureTypes = New Collection

    Set Component = Application.VBE.ActiveVBProject.VBComponents(modName)
        With Component.CodeModule

            ' Remove empty lines on the end of the code
            For i = .CountOfLines To 1 Step -1
                If Component.CodeModule.Lines(i, 1) = "" Then
                  Component.CodeModule.DeleteLines i, 1
                Else
                    Exit For
                End If
            Next i

            Index = .CountOfDeclarationLines + 1
            Do While Index < .CountOfLines
                gotoErr = False
                Name = .ProcOfLine(Index, Kind)
                FirstLine = .ProcBodyLine(Name, Kind)
                ProcLinesCount = .ProcCountLines(Name, Kind)
                Declaration = Trim(.Lines(FirstLine, 1))
                LastLine = FirstLine + ProcLinesCount - 2
                If InStr(1, Declaration, "Function ", vbBinaryCompare) > 0 Then
                    ProcedureType = "Function"
                Else
                    ProcedureType = "Sub"
                End If
                Debug.Print Component.Name & "." & Name, "First: " & FirstLine, "Lines:" & ProcLinesCount, "Last: " & LastLine, Declaration
                Debug.Print "Declaration: " & Component.CodeModule.Lines(FirstLine, 1), FirstLine
                Debug.Print "Closing Proc: " & Component.CodeModule.Lines(LastLine, 1), LastLine

                ' do not insert error handling if there is one already:
                For i = FirstLine To LastLine Step 1
                    If Component.CodeModule.Lines(i, 1) Like "*On Error*" Then
                        gotoErr = True
                        Exit For
                    End If
                Next i
                If Not gotoErr Then
                    StartLines.Add FirstLine
                    LastLines.Add LastLine
                    ProcNames.Add Name
                    ProcedureTypes.Add ProcedureType
                End If

                Index = FirstLine + ProcLinesCount + 1
            Loop

            For i = LastLines.Count To 1 Step -1
                If Not (Component.CodeModule.Lines(StartLines.Item(i) + 1, 1) Like "*On Error GoTo *") Then
                    Component.CodeModule.InsertLines LastLines.Item(i), "ExitProc_:"
                    Component.CodeModule.InsertLines LastLines.Item(i) + 1, "    Exit " & ProcedureTypes.Item(i)
                    Component.CodeModule.InsertLines LastLines.Item(i) + 2, "ErrHandler_:"
                    Component.CodeModule.InsertLines LastLines.Item(i) + 3, "    Call LogError(Err, Me.Name, """ & ProcNames.Item(i) & """)"
                    Component.CodeModule.InsertLines LastLines.Item(i) + 4, "    Resume ExitProc_"
                    Component.CodeModule.InsertLines LastLines.Item(i) + 5, "    Resume ' use for debugging"

                    Component.CodeModule.InsertLines StartLines.Item(i) + 1, "    On Error GoTo ErrHandler_"
                End If
            Next i
        End With
End Sub

これをモジュールに入れて、次のようなフォームまたはモジュールに新しい関数またはサブを追加するたびに、イミディエイトウィンドウから呼び出します(Form1はフォームの名前です)。

MyModule.InsertErrHandling "Form_Form1"

これにより、Form1のodeが次のように変更されます。

Private Function CloseIt()
    DoCmd.Close acForm, Me.Name
End Function

これに:

Private Function CloseIt()
    On Error GoTo ErrHandler_
        DoCmd.Close acForm, Me.Name
ExitProc_:
Exit Function
ErrHandler_:
    Call LogError(Err, Me.Name, "CloseIt")
    Resume ExitProc_
    Resume ' use for debugging
End Function

エラーダイアログを表示し、テキストファイルまたはデータベースへのエラーの挿入を追加できるSubをモジュールに作成します。

Public Sub LogError(ByVal objError As ErrObject, moduleName As String, Optional procName As String = "")
    On Error GoTo ErrHandler_
    Dim sql As String
    MsgBox "Error " & Err.Number & " Module " & moduleName & Switch(procName <> "", " in " & procName) & vbCrLf & " (" & Err.Description & ") ", vbCritical
Exit_:
    Exit Sub
ErrHandler_:
    MsgBox "Error in LogError procedure " & Err.Number & ", " & Err.Description
    Resume Exit_
    Resume ' use for debugging
End Sub

プロシージャにすでに「OnError」ステートメントがある場合、このコードはエラー処理を入力しません。

2
Vlado