簡體   English   中英

MS-Access,VBA和錯誤處理

[英]MS-Access, VBA and error handling

這更像是一個觀察而不是一個真實的問題:MS-Access(以及一般的VBA)極度缺少一個可以自動生成錯誤處理代碼的工具,以及發生錯誤時可以顯示行號的工具。 你找到了解決方案嗎? 它是什么? 我剛剛意識到,自從幾年前我找到了解決這個基本問題的正確答案以來,我有多少個小時,我希望看到你在這個非常重要的問題上有什么想法和解決方案。

如何使用“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

我的解決方案如下:

  1. 安裝MZ-Tools ,這是一個非常有趣的VBA附加組件。 不,他們沒有付我寫這個。 版本3是免費的,但自8.0版以來,該插件已在商業上銷售。
  2. 編寫一個標准的錯誤處理程序代碼,例如這個(參見MZ-Tools菜單/選項/錯誤處理程序):

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一起使用的自動錯誤報告系統

那么有一些工具可以滿足您對MZ ToolsFMS Inc的想法。

基本上他們涉及添加:

On Error GoTo ErrorHandler

到每個過程的頂部,最后他們把:

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

標簽通常調用全局錯誤處理程序,您可以在其中顯示和記錄自定義錯誤消息

你總是可以像Chip Pearson那樣推出自己的工具。 VBA實際上可以通過Microsoft Visual Basic for Applications Extensibility 5.3 Library訪問它自己的IDE。 我編寫了一些類模塊,可以更輕松地與自己合作。 它們可以在Code Review SE上找到。

我用它來插入On Error GoTo ErrHandler語句以及與我的錯誤處理模式相關的相應標簽和常量。 我還使用它來將常量與實際的過程名稱同步(如果函數名稱應該發生變化)。

沒有必要購買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中的頌歌:

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

如果proc中已存在“On Error”語句,則此代碼不會進入錯誤處理。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM