Automatically generating handling of issues

前端 未结 5 714
旧时难觅i
旧时难觅i 2020-11-27 18:53

This is more an observation than a real question: MS-Access (and VBA in general) is desperately missing a tool where error handling code can be generated automatically, and

5条回答
  •  忘掉有多难
    2020-11-27 19:56

    There is no need to buy tools DJ mentioned. Here is my code for free:

    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
    

    Put it in a module and call it from Immediate Window every time you add new function or sub to a form or module like this (Form1 is name of your form):

    MyModule.InsertErrHandling "Form_Form1"
    

    It will alter your ode in Form1 from this:

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

    to this:

    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
    

    Create now in a module a Sub which will display the error dialog and where you can add inserting the error to a text file or database:

    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
    

    This code does not enter error handling if there is already "On Error" statement in a proc.

提交回复
热议问题