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

How to handle error generated inside another workbook's Workbook_Open event?

我在同一文件夹中有两个工作簿: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 在模块 1 中有以下代码:

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() 事件中有这样的错误代码,如果程序因这样的未处理错误而崩溃,我将无法遍历它们.

错误没有被处理的原因是两个进程不在同一个线程中。如果您从主子过程调用 'helper' 子过程,您将保留在同一个线程中,并且 'helper' 中抛出的错误会被主过程中的错误控制捕获。这类似于为什么 Application.Run 启动的过程中的错误不会引发由启动它的过程中的错误控制处理的错误。

要对新打开的工作簿 Workbook_Open 中发生的事情进行任何控制,您需要在应用程序实例级别进行控制。以下停止执行 Workbook_Open 事件过程;如果不需要处理代码,那么这可能是您的解决方案。

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

如果字典填充是您要克服的特定错误,请使用覆盖重复项的字典 shorthand 方法。

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

错误未得到处理,因为新打开的工作簿 运行 在基本上是异步进程的内部 - 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 的运行至关重要,那么您可以使用解决方案 。只需在目标工作簿中创建一个 public 包装函数,然后从您自己的错误处理程序的上下文中调用它。