我可以从Microsoft Access VBA中的当前事件堆栈返回吗?

时间:2017-02-27 17:56:25

标签: vba ms-access exception events access-vba

我想知道是否存在预先构建的系统函数,该函数将取消当前正在触发的事件的整个内存堆栈,而不必退出Microsoft Access VBA中的堆栈跟踪中的每个过程?

我正在寻找以下内容:

Public Sub Procedure2()
    CancelEvent 'This would return from procedure2, proedure1, and the specific event Sub
End Sub

Public Sub Procedure1()
    Procedure2
End Sub

Private Sub SomeControl_SomeEvent()
    Procedure1
End Sub

我已经尝试过DoCmd.CancelEvent,但程序执行后仍然继续,并且不取消整个过程堆栈(我可能一直在寻找错误的系统Sub)。我能想到实现这个目的的唯一方法(没有讨厌的If-Else语句来检查下面的堆栈过程是否必须继续,如果我退出上面的堆栈过程)是使用异常,并具有如下内容:< / p>

Public Sub Procedure2()
    Err.Raise 1  'Just an example exception
End Sub

Public Sub Procedure1()
    Procedure2
End Sub

Private Sub SomeControl_SomeEvent()
    On Error Goto HandleError
    Goto StartSub
HandleError:
    Exit Sub
StartSub:
    Procedure1
End Sub

或者,是否可以仅在VBA中捕获特定的异常,因为我可能只需要在最低的堆栈过程中捕获此异常?

1 个答案:

答案 0 :(得分:4)

必须将其作为错误处理策略实施。

我定义了一个公共枚举来正式跟踪(并命名)自定义错误代码,从vbObjectError +某个值开始:

Public Enum CustomError
    CE_Cancelled = vbObjectError + 42
    CE_SomeOtherCustomError
    '...
End Enum

然后当你想“取消”一个事件并“走上调用堆栈”时,你可以提出那个错误:

Public Sub RaiseOperationCancelledError(ByVal source As String)
    Err.Raise CE_Cancelled, source, "Operation was cancelled."
End Sub

RaiseOperationCancelledError运行时究竟会发生什么,完全取决于此时调用堆栈中的On Error语句。

假设您在调用堆栈的顶部(实际上是erm, bottom )有一些控制事件:

Private Sub SomeControl_SomeEvent()
    On Error Goto CleanFail
    DoSomething
CleanExit:
    Exit Sub
CleanFail:
    If Err.Number = CE_Cancelled Then
        MsgBox Err.Description '"Operation was cancelled."
    Else
        Err.Raise Err.Number 'we don't know what happened; rethrow.
    End If
    Resume CleanExit
End Sub

如果DoSomething有,IDK,说文件I / O,需要处理错误:

Sub DoSomething()
    On Error GoTo CleanFail
    Dim fileNumber As Long
    fileNumber = FreeFile
    'do stuff
    '...
CleanExit:
    Close fileNumber
    Exit Sub
CleanFail:
    If Err.Number = 53 Then
        ' handle "file not found" error
        Resume CleanExit
    Else If Err.Number = CE_Cancelled Then
        Close fileNumber ' we won't run CleanExit if we rethrow!
        Err.Raise Err.Number ' rethrow
    End If
End Sub

现在,这几乎和它一样邋..那有什么问题?

问题是你正在为流量控制使用自定义运行时错误,并且不可避免地会变成任何语言的意大利面条代码,无论是否有例外。

如果您正在做某事并且用户取消了它,那么您将拥有一个返回一个值的函数,该值可以准确地告诉您 - 例如用户取消了文件浏览器对话框,我们无法继续导出 - 您不会引发自定义错误!相反,你创建了一个函数,它的职责是返回用户选择的文件,使用一些机制告诉它的调用者毕竟不会有一个导出目标 - 该函数可能返回一个空字符串而不是一个有效的文件路径;然后调用者知道如果返回的字符串为空,则需要挽救并返回其自己的调用者,自然地解除调用堆栈