繁体   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