如果我正在阅读您正确执行的操作,那么这与我第一次开始做类似事情时陷入的陷阱相同。问题在于,因为错误是在非主程序中“处理”的,所以就错误处理系统而言,它已经完成并除尘了;当程序控制流返回到主程序时,不再有错误情况。让我看看我是否可以用伪代码说明:
MainFunction()
On Error Goto ErrorHandler
Call MySubFunction
CodeToSendSuccessEmail
ExitPoint:
'Here we do any necessary cleanup.
Exit Function
ErrorHandler:
Call MyErrorRoutine
Resume ExitPoint
End Function
Function MySubFunction()
On Error Goto ErrorHandler
DoStuffThatCauseAnError
ExitPoint:
Exit Function
ErrorHandler:
Call MyErrorRoutine
Resume ExitPoint
End Function
好的,那么当 MySubFunction 发生错误时会发生什么?它将跳转到该函数中的 ErrorHandler: 标签。完成此操作后,就错误处理系统而言,错误已得到处理,因此它将离开该函数(在我的例子中,通过 ExitPoint: label 和 Exit Function 语句)并返回到 MainFunction。当它这样做时,将不再有错误,因为它已被处理,因此将发送“成功”电子邮件。
处理此类情况的最快和最肮脏的方法是根本不在子过程中放置任何错误处理。这样,当发生错误时,它将立即被抛出调用堆栈,直到遇到错误处理程序,在这种情况下,该处理程序将在您的 MainFunction 中。当它这样做时,它会直接跳到 MainFunction 的 ErrorHandler: 标签。
这样做的缺点是您无法准确跟踪错误发生在哪个函数中。我在实践中所做的是让我的子例程错误处理程序执行此操作: (a) 调用我的跟踪程序来编写错误(及其位置)到我的应用程序的日志文件;(b) 注意变量中的 Err.Number 和 Err.Description;然后 (c) 在我返回 ExitPoint: 标签后,使用这些变量中的值重新引发错误,以便它会流回堆栈。
这样可以确保我知道错误的来源,但是向用户显示错误消息的主要显示(在您的情况下,通过写入表格并发送电子邮件)将发生一次,并且仅发生一次;也就是说,仅通过我的顶级函数调用我的主要错误例程。
顺便说一句,当我第一次遇到它时,我对 VB.Net 和 T-SQL 中使用的 Try/Catch 语法持怀疑态度,但实际上它在错误处理方面确实提供了很多优势,包括不需要捏造发生错误时跟踪堆栈。并不是说您在 Access 中使用 VBA 有一点好处;正如我所说,这只是一个旁白。