Arhn - архитектура программирования

Как обработать ошибку, сгенерированную внутри события Workbook_Open другой книги?

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


  • Вы можете попробовать отключить события - если вам не нужно запускать событие Workbook_Open 01.09.2018
  • @urdearboy спасибо, это возможно, но я хотел бы выборочно перехватывать ошибки, чтобы, например. если у книги возникли проблемы с открытием из-за повреждения, мы обработали бы эту ошибку по-другому (например, пропустив эту книгу в цикле) 01.09.2018
  • Если это конкретная ошибка, которую вы пытаетесь преодолеть, либо используйте метод сокращения словаря, который перезаписывает дубликаты, либо, в более общем смысле, обертывайте потенциальные ошибки в On Error Resume Next и On Error GoTo 0. 01.09.2018

Ответы:


1

Причина того, что ошибка не обрабатывается, заключается в том, что два процесса не находятся в одном потоке. Если вы вызывали «вспомогательную» подпроцедуру из основной подпроцедуры, вы остаетесь в том же потоке, а ошибки, выдаваемые «помощником», перехватываются контролем ошибок в основном. Это похоже на то, почему ошибка в процедуре, запущенной 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
31.08.2018
  • Его проблема - необработанная ошибка. Я демонстрирую два метода обхода ошибки согласно 'И как я могу обработать эту ошибку?' 01.09.2018
  • Но он хочет обрабатывать это из bkOpenErrorTest.xlsm, а не из bkOpenErrorTest_dict.xlsm. 01.09.2018
  • ... и когда он придет к пониманию, что этого просто никогда не произойдет, тогда он может рассмотреть эти варианты. 01.09.2018
  • Разве вы не должны тогда в своем ответе сообщить ему, что то, что он хочет, никогда не сработает? 01.09.2018
  • Возможно, я сделаю это после того, как найду время, чтобы настроить несколько внешних рабочих книг и протестировать каждый сценарий и возможное решение, которое я могу придумать. На данный момент тот факт, что созданная рабочая книга не находится в том же потоке, что и вызывающая подпроцедура, является причиной того, что обработка ошибок вызывающей подпроцедуры не охватывает ошибку, возникшую в новой рабочей книге. 01.09.2018
  • Я не могу программно изменить код в bkOpenErrorTest_dict, потому что он вылетает каждый раз, когда я его открываю. А учитывая, что в моем случае нужно перебирать сотни рабочих книг, ручное изменение кода нецелесообразно. 01.09.2018
  • @sigil - происходит сбой, потому что у вас включены события. Отключите их, чтобы избежать событий, затем измените код, как только у вас будет действительная ссылка. 01.09.2018
  • Я собираюсь воспользоваться рекомендацией этого ответа об отключении обработки событий, поскольку кажется, что невозможно сделать что-либо еще, кроме как вручную изменить код целевой книги. 01.09.2018

  • 2

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

    31.08.2018
  • Как я уже упоминал в своем комментарии к ответу Jeeped, изменение кода в целевой книге нецелесообразно из-за большого количества книг, которые мне нужно решить. 01.09.2018
  • Тогда этот ответ должен объяснить, почему то, что вы хотите сделать, невозможно. ;-) 01.09.2018
  • @sigil Также обратите внимание, что вам не нужно сохранять код, который вы отправляете в рабочие книги через связанный ответ, — вам просто нужно вызвать его . 01.09.2018
  • если программа аварийно завершает работу при открытии рабочей книги, тогда код, изменяющий VBA, не может быть вставлен для запуска (поскольку программа, которая должна была вставить код, больше не выполнялась). 01.09.2018
  • @sigil Посмотрите еще раз на код в ответе. Если вы отключите события, событие Workbook_Open не будет запускаться, поэтому оно не может завершить работу. 01.09.2018
  • Новые материалы

    Коллекции публикаций по глубокому обучению
    Последние пару месяцев я создавал коллекции последних академических публикаций по различным подполям глубокого обучения в моем блоге https://amundtveit.com - эта публикация дает обзор 25..

    Представляем: Pepita
    Фреймворк JavaScript с открытым исходным кодом Я знаю, что недостатка в фреймворках JavaScript нет. Но я просто не мог остановиться. Я хотел написать что-то сам, со своими собственными..

    Советы по коду Laravel #2
    1-) Найти // You can specify the columns you need // in when you use the find method on a model User::find(‘id’, [‘email’,’name’]); // You can increment or decrement // a field in..

    Работа с временными рядами спутниковых изображений, часть 3 (аналитика данных)
    Анализ временных рядов спутниковых изображений для данных наблюдений за большой Землей (arXiv) Автор: Рольф Симоэс , Жильберто Камара , Жильберто Кейрос , Фелипе Соуза , Педро Р. Андраде ,..

    3 способа решить квадратное уравнение (3-й мой любимый) -
    1. Методом факторизации — 2. Используя квадратичную формулу — 3. Заполнив квадрат — Давайте поймем это, решив это простое уравнение: Мы пытаемся сделать LHS,..

    Создание VR-миров с A-Frame
    Виртуальная реальность (и дополненная реальность) стали главными модными терминами в образовательных технологиях. С недорогими VR-гарнитурами, такими как Google Cardboard , и использованием..

    Демистификация рекурсии
    КОДЕКС Демистификация рекурсии Упрощенная концепция ошеломляющей О чем весь этот шум? Рекурсия, кажется, единственная тема, от которой у каждого начинающего студента-информатика..