Vba 自动生成问题处理

Vba 自动生成问题处理,vba,ms-access,error-handling,Vba,Ms Access,Error Handling,这与其说是一个真正的问题,不如说是一个观察:MS Access(以及通常的VBA)非常缺少一个可以自动生成错误处理代码的工具,并且在发生错误时可以显示行号。你找到解决办法了吗?这是怎么一回事?我刚刚意识到,自从几年前我找到了这个基本问题的正确答案以来,我节省了数百个小时,我想看看你在这个非常重要的问题上有什么想法和解决方案 好吧,有两种工具可以满足您的要求并让您想起 基本上,它们包括添加一个: On Error GoTo ErrorHandler 到每个过程的顶部 最后,他们提出: Error

这与其说是一个真正的问题,不如说是一个观察:MS Access(以及通常的VBA)非常缺少一个可以自动生成错误处理代码的工具,并且在发生错误时可以显示行号。你找到解决办法了吗?这是怎么一回事?我刚刚意识到,自从几年前我找到了这个基本问题的正确答案以来,我节省了数百个小时,我想看看你在这个非常重要的问题上有什么想法和解决方案

好吧,有两种工具可以满足您的要求并让您想起

基本上,它们包括添加一个:

On Error GoTo ErrorHandler
到每个过程的顶部 最后,他们提出:

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

标签中通常包含对全局错误处理程序的调用,您可以在其中显示和记录自定义错误消息。我的解决方案如下:

  • install,一个非常有趣的VBA附加组件。不,他们没有付钱让我写这个。版本3是免费的,但从版本8.0开始,该附加模块已在商业上销售
  • 编写一个标准错误处理程序代码,如以下代码(请参阅MZ工具菜单/选项/错误处理程序):


  • 然后,通过单击MZ工具菜单中的相应按钮,可以将此标准错误代码自动添加到所有程序和功能中。您会注意到,这里我们指的是VBA标准库中的一个隐藏且未记录的函数“Erl”,它代表“error line”。你说对了!如果您要求MZ工具自动为代码行编号,“Erl”将为您提供发生错误的代码行编号。您将在即时窗口中完整描述错误,例如:

    #91, Object variable or With block variable not set, l# 30, addNewField, Utilities
    
    当然,一旦您意识到系统的重要性,您可以考虑一个更复杂的错误处理程序,它不仅会在调试窗口中显示数据,而且还会:

  • 将其显示为屏幕上的消息
  • 自动在错误日志文件中插入一行,其中包含错误说明
  • 如果您使用Access或连接到数据库,请自动将记录添加到Tbl_错误表中 这意味着在用户级别生成的每个错误都可以存储在计算机或网络上的某个位置的文件或表中。我们是在谈论建立一个自动化的错误报告系统吗?使用VBA?

    使用“Erl”如何,它将显示错误之前的最后一个标签(例如,10、20或30)


    您可以像以前一样滚动自己的工具。VBA实际上可以通过访问自己的IDE。我已经编写了一些类模块,使自己的工作更容易。可以在上找到它们


    我使用它插入
    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中的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
    
    现在在模块中创建一个子模块,该子模块将显示错误对话框,您可以在其中将错误添加到文本文件或数据库:

    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
    
    Public子日志错误(ByVal objError作为ErrObject,moduleName作为String,可选procName作为String=”“)
    关于错误转到错误处理程序_
    将sql设置为字符串
    MsgBox“Error”和errr.Number&“Module”和moduleName&Switch(procName中的“,”)&vbCrLf&(“&Err.Description&”),vbCritical
    退出:
    出口接头
    错误处理程序:
    MsgBox“日志错误过程中的错误”&错误编号&“,”错误描述
    恢复退出_
    “恢复”用于调试
    端接头
    

    如果进程中已经有“On error”语句,则此代码不会进入错误处理。

    Good post,但我批评错误处理程序和退出例程没有统一名称的做法,例如errHandler和exitRoutine。由于标签范围的原因,没有理由将其特定于特定子项。这样可以更轻松地剪切和粘贴helluv。您是对的:无需为错误例程指定特定名称。但这并不重要,因为您不会从一个过程复制/粘贴到另一个过程,而是使用“插入错误代码”按钮,该按钮根据预定义的格式生成所需的行。错误时转到0是不必要的行,因为您将在下一行退出该过程。On Error Goto ErrorHandler语句在过程之外不适用这有点误导,因为Err.LineNumber不存在。。因此,虽然通用错误处理的良好实践,但它并没有回答关于行编号的原始问题的关键。如果您需要这样做,那么如果您必须有行号,那么涉及Erl的答案会更好。您不希望在代码中使用行号。读这篇:注意到了,同意了。我不想要行号。我的开发代码中没有任何行号。然后,当涉及到我的应用程序的用户版本时,我希望能够记录用户生成的错误,我正在添加它们(以自动方式),使错误跟踪变得更容易:(1)至少我可以检查来自特定模块的错误是否确实相同;(2)调试代码更快。当然,我没有任何超过65000行的程序!
    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
    
    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