这更像是一个观察而不是一个真实的问题: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
我的解决方案如下:
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
当然,一旦你意识到系统的兴趣,你就可以想到一个更复杂的错误处理程序,它不仅会在调试窗口中显示数据,还会:
意味着在用户级别生成的每个错误都可以存储在文件或表中,机器或网络上的某个位置。我们是否正在讨论构建与VBA一起使用的自动错误报告系统?
你总是可以像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”语句,则此代码不会进入错误处理。