如何处理在另一个工作簿的Workbook_Open事件中生成的错误?

时间:2018-08-31 21:52:47

标签: excel vba excel-vba exception-handling

我在同一文件夹中有两个工作簿:bkOpenErrorTest.xlsmbkOpenErrorTest_dict.xlsm

bkOpenErrorTest_dict.xlsm在其ThisWorkbook模块中具有以下代码:

Private Sub workbook_open()

Dim dict As Dictionary

Set dict = New Dictionary
dict.Add 0, 0
dict.Add 0, 0

End Sub

通过双击文件名打开此工作簿时,它将引发预期的未处理错误:

This key is already associated with an element of this collection

bkOpenErrorTest.xlsm在Module1中具有以下代码:

Sub testOpen()

Dim bk As Workbook

On Error GoTo errHandler

Workbooks.Open ThisWorkbook.Path & "\bkOpenErrorTest_dict.xlsm"

Exit Sub

errHandler:
Debug.Print "reached error handler"

End Sub

当错误陷阱设置为Break on Unhandled Errors,并且我运行testOpen()时,bkOpenErrorTest_dict.xlsm打开时仍会引发未处理的错误。为什么testOpen()的错误处理程序未捕获该错误?我该如何处理该错误?我有一个应用程序,我想在一个文件夹中循环浏览许多工作簿,这些工作簿在其workbook_open()事件中具有这样的错误代码,并且如果程序由于诸如此类的未处理错误而崩溃,则无法遍历它们

2 个答案:

答案 0 :(得分:4)

未处理错误的原因是两个进程不在同一线程中。如果要从主子过程中调用“帮助程序”子过程,则您将保持在同一线程中,并且在“帮助程序”中引发的错误会被主程序中的错误控制捕获。这类似于为什么Application.Run启动的过程中的错误不会引发由启动它的过程中的错误控件处理的错误。

要获得对新打开的工作簿的Workbook_Open中发生的情况的控制,您需要在Application实例级别上进行控制。下面的步骤停止执行Workbook_Open事件过程;如果不需要处理代码,那么这可能是您的解决方案。

Application.EnableEvents = False
Set bk = Workbooks.Open(ThisWorkbook.Path & "\bkOpenErrorTest_dict.xlsb")
Application.EnableEvents = True

如果“字典填充”是您要解决的特定错误,请使用覆盖副本的字典速记方法。

Dim dict As Dictionary

Set dict = New Dictionary
dict.Item(0) = 0
dict.Item(0) = 1
'dict.count = 1 with key as 0 and item as 1

通常,您可以将潜在错误包装在On Error Resume Next和On Error GoTo 0中。

Dim dict As Dictionary

Set dict = New Dictionary
On Error Resume Next
dict.Add 0, 0
dict.Add 0, 1
On Error GoTo 0
'dict.count = 1 with key as 0 and item as 0

答案 1 :(得分:4)

该错误未得到处理,因为新打开的工作簿在基本上是异步过程的内部运行-Workbook_Open事件处理程序,因此不会从您的代码中调用它。无论外部Excel进程正在打开文档如何,都将其作为回调函数来调用。您可以使用 any 事件处理程序演示相同的行为:

'In Sheet1
Sub Example()
    On Error GoTo Handler
    Sheet1.Cells(1, 1).Value = "Foo"
    Exit Sub

Handler:
    Debug.Print "Handled"
End Sub

Private Sub Worksheet_Change(ByVal Target As Range)
    If Target.Row = 1 And Target.Column = 1 Then
        Err.Raise 6
    End If
End Sub

如果您需要批量处理文件,则唯一的(简单)选项将是在打开调用之前禁用事件:

Sub testOpen()
    Dim bk As Workbook

    On Error GoTo errHandler

    Application.EnableEvents = False
    Set bk = Workbooks.Open ThisWorkbook.Path & "\bkOpenErrorTest_dict.xlsm"
    Application.EnableEvents = True

    Exit Sub

errHandler:
    Debug.Print "reached error handler"
End Sub

如果出于某种原因,越野车Workbook_Open运行至关重要,那么您可以使用解决方案Tim Williams outlines here。只需在目标工作簿中创建一个公共包装函数,然后在您自己的错误处理程序的上下文中调用它即可。