Как обработать ошибку, созданную в событии Workbook_Open другой книги? - PullRequest
0 голосов
/ 01 сентября 2018

У меня две книги в одной папке: bkOpenErrorTest.xlsm и bkOpenErrorTest_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(), и я не могу просмотреть их, если программа вылетает из-за необработанной ошибки, подобной этой.

Ответы [ 2 ]

0 голосов
/ 01 сентября 2018

Ошибка не обрабатывается, потому что недавно открытая Рабочая книга выполняется внутри того, что по сути является асинхронным процессом - Workbook_Open является обработчиком событий , поэтому она не вызывается из вашего кода. Он вызывается как функция обратного вызова из любого внешнего процесса Excel, открывающего документ. То же поведение можно продемонстрировать с помощью любого обработчика событий:

'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, то вы можете использовать решение Обрисованное Тимом Уильямсом здесь . Просто создайте общедоступную функцию-обертку в целевой книге, а затем вызовите ее в контексте вашего собственного обработчика ошибок.

0 голосов
/ 01 сентября 2018

Причина, по которой ошибка не обрабатывается, заключается в том, что два процесса не находятся в одном потоке. Если вы вызывали подпроцедуру «помощник» из основной подпроцедуры, вы остаетесь в том же потоке, и ошибки, генерируемые в «помощнике», обнаруживаются контролем ошибок в главном. Это похоже на то, почему ошибка в процедуре, запущенной Application.Run, не будет приводить к ошибкам, обработанным контролем ошибок в процедуре, которая ее запустила.

Чтобы получить какой-либо контроль над тем, что происходит в недавно открытой рабочей книге Workbook_Open, вам нужно контролировать вещи на уровне экземпляра приложения. Следующее останавливает выполнение процедуры события 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...