Меню

Продолжить макрос при ошибке

 

Framed

Пользователь

Сообщений: 223
Регистрация: 25.01.2018

#1

04.03.2019 19:39:20

Коллеги, приветствую,

Немного запутался в теме про обработчик ошибок, хотя, скорее всего, я нашёл ответ на вопрос в

этой теме

, просто не могу его понять до конца.

Необходимо, чтобы в случае ошибки, которая возникает в определенный момент в коде, часть кода пропускалась, появлялся MsgBox с определенным текстом, после чего макрос продолжал бы работать в нормальном режиме (если будет какая-нибудь другая ошибка далее — выскочит диалоговое окно).

Знаю, что задача простая, ну вот туплю что-то…

Код
            On Error GoTo ErrorHandler            
            Set iWb = GetObject("C:UsersA670669DesktopSCR_Managers.xlsx")
            iLastRowSCR = iWb.Sheets(1).Cells(Rows.Count, 1).End(xlUp).row
            Set iBodySCR = iWb.Sheets(1).Range("B2:M" & iLastRowSCR)
            iWb.Names.Add Name:="BodySCR", RefersTo:=iBodySCR
            With .ListColumns("Rate").DataBodyRange
                .Formula = "=IFERROR(VLOOKUP(A3,SCR_Managers.xlsx!BodySCR,12,0),0)"
                .Cells.Value = .Cells.Value
            End With
            iWb.Close False
ErrorHandler:
            MsgBox "Произошла ошибка"
            On Error Resume Next

На данный момент все как надо, только вот когда даже ошибки нет вылезает MsgBox.

Заранее спасибо.

P.S. Как-то криво написал название темы, должна была быть VBA: Обработчик ошибок, пропуск кода и продолжение выполнения макроса.

Изменено: Framed05.03.2019 00:54:10

 

Anchoret

Пользователь

Сообщений: 1034
Регистрация: 01.01.1970

Anchoret

#2

04.03.2019 19:44:33

Код
On Error Resume Next
If Err then Goto ...
 

Framed

Пользователь

Сообщений: 223
Регистрация: 25.01.2018

#3

04.03.2019 19:52:06

Anchoret, вот так?

Код
 On Error Resume Next
            MsgBox "Произошла ошибка"
            If Err Then GoTo ErrorHandler
            Set iWb = GetObject("C:UsersA670669DesktopSCR_Managers.xlsx")
            iLastRowSCR = iWb.Sheets(1).Cells(Rows.Count, 1).End(xlUp).row
            Set iBodySCR = iWb.Sheets(1).Range("B2:M" & iLastRowSCR)
            iWb.Names.Add Name:="BodySCR", RefersTo:=iBodySCR
            With .ListColumns("Rate").DataBodyRange
                .Formula = "=IFERROR(VLOOKUP(A3,SCR_Managers.xlsx!BodySCR,12,0),0)"
                .Cells.Value = .Cells.Value
            End With
            iWb.Close False
ErrorHandler:






 

Sanja

Пользователь

Сообщений: 14837
Регистрация: 10.01.2013

#4

04.03.2019 19:54:37

Цитата
Framed написал: только вот когда даже ошибки нет вылезает MsgBox

Обработчик ошибок поместите в самый конец кода, а перед ним должна быть строка Exit Sub

Код
On Error GoTo ErrorHandler
    Set iWb = GetObject("C:UsersA670669DesktopSCR_Managers.xlsx")
    iLastRowSCR = iWb.Sheets(1).Cells(Rows.Count, 1).End(xlUp).Row
    Set iBodySCR = iWb.Sheets(1).Range("B2:M" & iLastRowSCR)
    iWb.Names.Add Name:="BodySCR", RefersTo:=iBodySCR
    With .ListColumns("Rate").DataBodyRange
        .Formula = "=IFERROR(VLOOKUP(A3,SCR_Managers.xlsx!BodySCR,12,0),0)"
        .Cells.Value = .Cells.Value
    End With
    iWb.Close False
    Exit Sub
'обработчик ошибок
ErrorHandler:
    MsgBox "Произошла ошибка"
End Sub

Согласие есть продукт при полном непротивлении сторон.

 

Framed

Пользователь

Сообщений: 223
Регистрация: 25.01.2018

#5

04.03.2019 20:03:30

Sanja, спасибо, но разве Exit Sub не остановит выполнение всего макроса, если ошибки не будет?

Я уточню, а то мне кажется, я плохо объяснил в шапке.

Код
'Код
'Код
'Код
 On Error GoTo ErrorHandler
            Set iWb = GetObject("C:UsersA670669DesktopSCR_Managers.xlsx")
            iLastRowSCR = iWb.Sheets(1).Cells(Rows.Count, 1).End(xlUp).row
            Set iBodySCR = iWb.Sheets(1).Range("B2:M" & iLastRowSCR)
            iWb.Names.Add Name:="BodySCR", RefersTo:=iBodySCR
            With .ListColumns("Rate").DataBodyRange
                .Formula = "=IFERROR(VLOOKUP(A3,SCR_Managers.xlsx!BodySCR,12,0),0)"
                .Cells.Value = .Cells.Value
            End With
            iWb.Close False
ErrorHandler:
            MsgBox "Произошла ошибка"
'Код
'Код
'Код

Выполняется макрос, и вот на 5 строке может выскочить ошибка, например, если файла нет, или его имя неверное. Мне нужно, чтобы в этом случае, часть кода 5-13 строка игнорировалась, не выполнялась и выскочил бы MsgBox c текстом, например, «Нет файла или имя некорректно». Далее код, который идет после ErrorHandler должен выполняться в обычном режиме (обычный режим для меня — это когда дальнейшие ошибки не вернут меня к ErrorHandler, простите за убогое объяснение).

В случае же, если ошибки на 5 строке моего примера не возникнет — код работает в штатном режиме.

Изменено: Framed04.03.2019 20:03:53

 

Anchoret

Пользователь

Сообщений: 1034
Регистрация: 01.01.1970

Anchoret

#6

04.03.2019 20:06:40

Framed,

Код
On Error Resume Next

перед строкой, в которой вероятна ошибка

Код
If Err then Goto ...

после такой строки. Ну и замечание от Sanja,

 

Framed

Пользователь

Сообщений: 223
Регистрация: 25.01.2018

Как-то не выходит. Дальнейшие ошибки в коде игнорируются, MsgBox вылезает, даже если ошибки не произошло.

 

БМВ

Модератор

Сообщений: 20899
Регистрация: 28.12.2016

Excel 2013, 2016

#8

04.03.2019 20:25:02

только наверно так

Код
'Код
'Код
'Код
 On Error resume next
            Set iWb = GetObject("C:UsersA670669DesktopSCR_Managers.xlsx")
            if err =0 then
                 iLastRowSCR = iWb.Sheets(1).Cells(Rows.Count, 1).End(xlUp).row
                 Set iBodySCR = iWb.Sheets(1).Range("B2:M" & iLastRowSCR)
                iWb.Names.Add Name:="BodySCR", RefersTo:=iBodySCR
                With .ListColumns("Rate").DataBodyRange
                    .Formula = "=IFERROR(VLOOKUP(A3,SCR_Managers.xlsx!BodySCR,12,0),0)"
                    .Cells.Value = .Cells.Value
                End With
                iWb.Close False
           else
                MsgBox "Произошла ошибка"
                err.clear  '  или on error goto 0
          end if
'Код
'Код
'Код
 

По вопросам из тем форума, личку не читаю.

 

Framed

Пользователь

Сообщений: 223
Регистрация: 25.01.2018

БМВ, спасибо, все отлично, только теперь в случае ошибки ниже End If, VBA продолжит выполнение кода, даже если, к примеру, название листа out of range и так далее.  

 

БМВ

Модератор

Сообщений: 20899
Регистрация: 28.12.2016

Excel 2013, 2016

Framed,  я не зря там написал ‘  или on error goto 0
В зависимости от потребностей или сбросить ошибку или и сбросить и прекратить обработку ошибок.
Конечно и через переход на метки можно сделать, но я отвык.

Изменено: БМВ04.03.2019 20:49:50

По вопросам из тем форума, личку не читаю.

 

Framed

Пользователь

Сообщений: 223
Регистрация: 25.01.2018

#11

04.03.2019 20:52:16

БМВ, простите, я проглядел. Спасибо большое за помощь, теперь я понял больше, без вас не разобрался бы.

Цитата
БМВ написал: Конечно и через переход на метки можно сделать, но я отвык.

Я где-то читал, что метки не приветствуются в VBA. Да и мне привычнее с операторами условия  :)  

 

БМВ

Модератор

Сообщений: 20899
Регистрация: 28.12.2016

Excel 2013, 2016

По вопросам из тем форума, личку не читаю.

 

vikttur

Пользователь

Сообщений: 47199
Регистрация: 15.09.2012

#13

05.03.2019 00:23:09

Цитата
Framed написал: метки не приветствуются в VBA.

Метки не беда, если не злоупотреблять и если они не нарушаюют (

не сильно нарушают

) структуру кода

 

Nordheim

Пользователь

Сообщений: 3154
Регистрация: 18.04.2017

Причина ошибки в данном куске кода в чем заключается?

«Все гениальное просто, а все простое гениально!!!»

 

Framed

Пользователь

Сообщений: 223
Регистрация: 25.01.2018

Nordheim, потенциально ошибка в том, что файл с таким названием может отсутствовать на рабочем столе у юзера. Этот файл (если он есть) в моем коде открывается, оттуда ВПР-ом подтягивается информация, после чего он закрывается. Если такого файла нет — мне нужно было, чтобы:

1. Выводилось сообщение со специальным текстом, т.е. MsgBox;
2. Пропускался кусок кода (который открывает файл, создает именной диапазон для ВПР, подтягивает куда надо данные с этого листа с помощью ВПР, превращает формулы в значения и закрывает книгу);
3. Макрос снова бы работал в обычном режиме (то есть в режиме «on error go to 0»).

Вообще, мне помогли и тему можно было закрывать, но раз уж вы спросили :)

БМВ, да, и я даже прочитал это несколько раз перед тем, как создать тему. Просто, откровенно говоря, не доходило до меня, как это правильно использовать; примеры из гугла не добавили ясности. Одним словом, еще учиться и учиться.

Изменено: Framed05.03.2019 14:33:07

 

Nordheim

Пользователь

Сообщений: 3154
Регистрация: 18.04.2017

#16

05.03.2019 14:45:40

Цитата
Framed написал:
Nordheim , потенциально ошибка в том, что файл с таким названием может отсутствовать на рабочем столе у юзера.

А если так:

Код
Sub test()
    Dim fname$, iPath$
    iPath = "C:UsersA670669DesktopSCR_Managers.xlsx"
    fname = Dir(iPath)
    If fname <> "" Then
        'обработка если файл существует
    Else: MsgBox "Произошла ошибка"
    End If
End Sub

Никакого On Error

PS:
Обработчик ошибок это конечно хорошо, вставил в начало и никаких проблем с кодом, зато потом вылезет какая ни-будь

«бяка»

в отчетах.

Изменено: Nordheim05.03.2019 14:48:24

«Все гениальное просто, а все простое гениально!!!»

 

Jack Famous

Пользователь

Сообщений: 10392
Регистрация: 07.11.2014

OS: Win 8.1 Корп. x64 | Excel 2016 x64: | Browser: Chrome

#17

05.03.2019 15:02:02

Framed, очень много чего вам посоветовали — лень читать всё))
1. В большинстве случаев от меток можно абсолютно безболезненно избавится, но иногда они помогают. Например, можно избежать «ветвления» кода далеко «вправо» — вот

ссылка

на тему с холиваром)))

Итак, в чём проблема… Всё просто — код доходит до строки ErrorHandler: MsgBox «Произошла ошибка» и выводит сообщение об ошибке (как и должен). Чтобы этого избежать, я обычно делаю, как в #4 (Sanja), но можно и «в лоб» обойти:

Код
GoTo nx
            iWb.Close False
ErrorHandler:
            MsgBox "Произошла ошибка"
nx:

— в таком случае, если мы дошли до GoTo nx, то просто «перепрыгиваем» ErrorHandler на метку nx. Если же произойдёт ошибка, то макрос «перепрыгнет» уже к метке ErrorHandler, минуя GoTo nx.

P.S.:

скорее всего, в вашем случае никакого On Error GoTo ErrorHandler не нужно — это подтверждает и наличие примеров, где легко без него можно обойтись. Я использую метки в основном, если нужно вернуться «выше по коду» (повтор ввода информации пользователем в случае ошибки) или, как уже сказал, чтобы избежать «ветвления» (многоуровневых вложенных «If—Else—End If»).
Но дело (как кодить) исключительно ВАШЕ  ;)

Изменено: Jack Famous05.03.2019 15:34:40

Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄

 

БМВ

Модератор

Сообщений: 20899
Регистрация: 28.12.2016

Excel 2013, 2016

#18

05.03.2019 15:21:22

Nordheim,
тут есть подвох, я с таким встречаюсь регулярно (правда не со скриптамии, но не суть)

Код
    iPath = "C:UsersA670669DesktopГод 2019Документы раздолбая" _
          & "Результаты совещания по вопросам бездумного использования длинных имен файлов и каталогов" _
          & "Выступление главного систематизатора……SCR_Managers.xlsx"

Короче, при полном пути более 260 символов, файл есть, он виден, но открыть его не возможно, впрочем как и скопировать или удалить, понятно что лучше в этом случае обработать длину пути, но порой проще просто обратится и обработать ошибку.
Вариант 2, это уже последствия сетевого доступа к общим файлам. При переносе файлов или каталогов права не наследуются от каталога в который поместили файлы , а сохраняются прежними. Это может привести к тому что также видеть видно, а вот прочесть никак. И в этом случае без обработки ошибки не обойтись.

Но в целом я полностью согласен, что обрабатывать ошибку надо там, где избежать её не возможно другими методами.

Jack Famous, так как я родом из VBS, а там нет Resume, то перешел на метку по ошибке, обратно не вернешься, что означает не продолжить с того же места. а это означает или куча меток и отдельные обработчики для каждой ошибки или …..

По вопросам из тем форума, личку не читаю.

 

Jack Famous

Пользователь

Сообщений: 10392
Регистрация: 07.11.2014

OS: Win 8.1 Корп. x64 | Excel 2016 x64: | Browser: Chrome

#19

05.03.2019 15:32:09

Цитата
БМВ: я родом из VBS

а я, стало быть, из VBA и могу использовать крутые штуки типа возврата наверх))

Вот такая, например

Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄

 

Nordheim

Пользователь

Сообщений: 3154
Регистрация: 18.04.2017

#20

05.03.2019 15:32:29

БМВ, На сколько я понимаю в данном случае путь прописывается руками, и визуально видно сколько символов.

Цитата
БМВ написал:
при полном пути более 260 символов, файл есть, он виден, но открыть его не возможно

Не сталкивался, потому наверное, что c Excel работаю постольку поскольку, это больше для саморазвития (интересные задания иногда встречаются).
Но теперь буду знать, а обработчиками в основном пользуюсь либо для заполнения коллекции либо в цикле где неправильный тип данных указывают и цикл не завершается пока ошибка не будет устранена.  ;)

«Все гениальное просто, а все простое гениально!!!»

 

БМВ

Модератор

Сообщений: 20899
Регистрация: 28.12.2016

Excel 2013, 2016

#21

05.03.2019 16:15:03

Цитата
Nordheim написал:
На сколько я понимаю в данном случае путь прописывается руками, и визуально видно сколько символов

да все верно, ремарка относилась скорее к тому, что бывает, когда невозможно отсечь возможность возникновения ошибки заранее.

По вопросам из тем форума, личку не читаю.

 

Казанский

Пользователь

Сообщений: 8839
Регистрация: 11.01.2013

#22

05.03.2019 16:56:51

Цитата
БМВ написал:
так как я родом из VBS, а там нет Resume, то перешел на метку по ошибке, обратно не вернешься

Забыл, забыл ты свою родину ;) Нет там меток, и GoTo только в конструкции On Error GoTo 0.

 

Framed

Пользователь

Сообщений: 223
Регистрация: 25.01.2018

Jack Famous, спасибо за разъяснения;
Nordheim, вам тоже большое спасибо, на самом деле, мне очень понравилось это решение, как и решение участника БМВ.
БМВ, спасибо за полезную информацию про ограничение.

Все-таки поясню: планируется, что файл, наличие которого проверяется, я буду высылать юзерам ежемесячно. У него относительно постоянная форма, меняются лишь данные. Соответственно, название файлу задаю тоже я. Файл носит вспомогательный характер. Вряд ли юзеры будут его переименовывать (я обязательно скажу, чтобы этого не делали) — их задача состоит лишь в том, чтобы один раз скопировать этот файл из Аутлука и куда-нибудь его закинуть, а после прописать корректный путь в VBA (а вот это им придется делать в любом случае самим, увы).

 

БМВ

Модератор

Сообщений: 20899
Регистрация: 28.12.2016

Excel 2013, 2016

#24

05.03.2019 18:47:08

Цитата
Казанский написал:
Забыл, забыл ты свою родину

🙂 вооот , там даже шанса не было 🙂 По сему и не применяю 🙂

По вопросам из тем форума, личку не читаю.

 

Nordheim

Пользователь

Сообщений: 3154
Регистрация: 18.04.2017

#25

05.03.2019 19:11:54

Цитата
Framed написал:
(а вот это им придется делать в любом случае самим, увы)

А если написать юзерам что бы сохранили файл с макросом и файл из которого берутся данные, в одну папку, то и прописывать ничего не нужно. Как вариант, можно сделать выбор файла.

«Все гениальное просто, а все простое гениально!!!»

 

RAN

Пользователь

Сообщений: 7081
Регистрация: 21.12.2012

#26

05.03.2019 19:48:22

Цитата
БМВ написал:
Короче, при полном пути более 260 символов

Еще короче. Для Exsel, кажется, 218 символов. Попадал.  :D

 

БМВ

Модератор

Сообщений: 20899
Регистрация: 28.12.2016

Excel 2013, 2016

#27

06.03.2019 08:03:50

Off

Цитата
RAN написал:
Для Exsel, кажется, 218 символов

Это не совсем про файл, а скорее про обращение к нему из самого Excel

https://support.microsoft.com/en-us/help/213983/error-message-when-you-open-or-save-a-file-in-microsoft-excel-filename

This behavior is based on a 256-character limitation in Excel for creating links to another file. This limit of 218 characters for the path name is based on the following:•Up to 31 characters in a sheet name.

•Apostrophes and brackets used to denote the workbook name.

•An exclamation point.

•A cell reference.

For example, the path for a file might resemple the following:

  ‘c:excelpersonal…[my workbook.xls]up_to_31_char_sheetname’!$A$1

Если перевести кратко, то, для работы с другой книгой, ссылка не может быть больше 256 символов, включая дополнительные символы (скобки,апострофы, восклицательный знак), имя листа  и диапазон.   если учесть что  Адрес может быть $AAA$1000000 (12 сим) +31 на имя листа + 5 на спец символы, то на путь останется менее 218ти
256-12-31-5=208

По вопросам из тем форума, личку не читаю.

 

Nordheim

Пользователь

Сообщений: 3154
Регистрация: 18.04.2017

#28

06.03.2019 08:54:26

В дополнении  

Цитата
Nordheim написал:
А если написать юзерам что бы сохранили файл с макросом и файл из которого берутся данные, в одну папку

Вариант файла с макросом при открытии запрашивает папку  для сохранения, затем сохраняет текущую книгу в указанную папку, и удаляет модуль с процедурой сохранения.
создал доп. модуль в котором дублировал код из удаляемого модуля, потому что после первого открытия его больше не будет. Может понадобится.

Прикрепленные файлы

  • Книга1.xlsm (16.3 КБ)

«Все гениальное просто, а все простое гениально!!!»

 

Framed

Пользователь

Сообщений: 223
Регистрация: 25.01.2018

#29

13.03.2019 17:36:49

Коллеги, прошу прощения заранее, что поднимаю старую тему и задаю в ней вопрос, но он связан с тем же макросом и с тем, что мне ответил пользователь Nordheim.

Цитата
Nordheim написал:
А если написать юзерам что бы сохранили файл с макросом

Файлы не с макросом, потому что модуль с ним находится в личной книге макросов.

Цитата
Nordheim написал:
Как вариант, можно сделать выбор файла.

Вот тут я хотел бы уточнить, если вы не против. Можно ли сделать такой алгоритм (но я точно не знаю, в самом макросе, или сделать отдельный), который поможет юзеру выбрать вспомогательный файл (как с сохранением, с помощью окна), а основной макрос бы ссылался на выбранный файл.

Зачем это нужно: планируются, что такие вспомогательные файлы будут отправляться юзерам раз в месяц, соответственно, можно их просто назвать одним именем и заменять один другим (как и реализованно в данный момент), но было бы лучше, если бы они сохранялись в специально созданной для этого папке, а юзеры могли бы просто «переключаться» между файлами, из которых нужно брать инфу.  

 

Jack Famous

Пользователь

Сообщений: 10392
Регистрация: 07.11.2014

OS: Win 8.1 Корп. x64 | Excel 2016 x64: | Browser: Chrome

#30

13.03.2019 18:02:32

Framed, если вопрос не связан с темой (Обработчик ошибок, пропуск куска кода), то создавайте новую

Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄

Excel VBA при ошибке Возобновить Далее

VBA при ошибке Возобновить Далее является оператором обработчика ошибок. Если ошибка возникает во время выполнения кода вместо отображения ошибки, чтобы возобновить следующую строку кода, игнорируя сообщение об ошибке, вы можете использовать этот оператор.

Те, кто регулярно пишет код в Excel VBA, знают, что они могут получать ошибки даже после написания профессионального кода, но они хотят игнорировать эту ошибку и продолжать работать со следующими строками кода. Типичным примером получения сообщения об ошибке является Функция рабочего листа ВПРФункция Excel ВПР ищет определенное значение и возвращает соответствующее совпадение на основе уникального идентификатора. Уникальный идентификатор однозначно связан со всеми записями базы данных. Например, идентификатор сотрудника, номер списка учащихся, контактный номер клиента, адрес электронной почты продавца и т. д. являются уникальными идентификаторами.
читать далее
не находит искомое значение в массиве таблиц. Он не вернет ошибку #N/A; скорее, он выдаст ошибку. Как «Невозможно получить свойство VLOOKUP класса функций рабочего листа».

VBA при ошибке Возобновление следующего примера 2.4

Если вы не знаете, почему мы получаем эту ошибку, то исправить ошибку очень сложно. В VBA у нас есть функция под названием «При ошибке Возобновить Далее».

Что делает при ошибке возобновление в VBA?

Есть определенные области в качестве кодера. Мы точно знаем, что это выдаст сообщение об ошибке, но нам нужно игнорировать эту ошибку, чтобы продолжить работу с кодом, поэтому вопрос о том, как игнорировать эту ошибку, вызывает общее сомнение у всех.

Используя оператор VBA On Error Resume Next, мы можем игнорировать ошибку и возобновить выполнение следующей строки кода.

Вы можете скачать этот шаблон VBA On Error Resume Next Excel здесь – VBA при ошибке Возобновить следующий шаблон Excel

Пример №1

Предположим, у вас много рабочих листов, и вы скрываете некоторые из них как часть проекта VBA. Например, ниже приведены рабочие листы, которые у меня есть на моем рабочем листе.

VBA при ошибке Возобновить следующий пример 1

Я написал коды, чтобы скрыть листы «Продажи и прибыль», и ниже приведен код.

Код:

Sub On_Error()

    Worksheets("Sales").Visible = xlVeryHidden
    Worksheets("Profit 2019").Visible = xlVeryHidden
    Worksheets("Profit").Visible = xlVeryHidden

End Sub

Пример 1.1

Теперь я начну выполнять код построчно, используя F8 ключ.

VBA при ошибке Возобновление следующего примера 1.2

Если я нажму на F8 ключ еще раз, он скроет лист с именем «Продажи».

Пример 1.3
VBA при ошибке Возобновление следующего примера 1.4

Теперь нажмите клавишу F8 еще раз и посмотрите, что произойдет.

VBA при ошибке Возобновление следующего примера 1.5

У нас есть «Индекс вне диапазонаИндекс вне диапазона — это ошибка в VBA, которая возникает, когда мы пытаемся сослаться на что-то или на переменную, которых нет в коде. Например, если у нас нет переменной с именем x, но мы используем функцию msgbox для x, мы получим ошибку нижнего индекса вне диапазона.читать далее», потому что текущая строка кода говорит следующее.

Worksheets("Profit 2019").Visible = xlVeryHidden

Он пытается скрыть рабочий лист с именем «Прибыль 2019,», но листа с названием «Прибыль 2019» нет.

В этих случаях, если рабочий лист не существует в рабочей книге, нам нужно проигнорировать ошибку и продолжить выполнение кода, игнорируя ошибку «Нижний индекс вне диапазона».

Следующая строка в коде говорит

Worksheets("Profit").Visible = xlVeryHidden

Этот рабочий лист существует в этой рабочей книге, поэтому, не игнорируя ошибку, мы не можем перейти к этой строке кода.

Чтобы игнорировать эту ошибку, нам нужно добавить оператор «При ошибке возобновить дальше».

Код:

Sub On_Error()

    On Error Resume Next
    Worksheets("Sales").Visible = xlVeryHidden
    Worksheets("Profit 2019").Visible = xlVeryHidden
    Worksheets("Profit").Visible = xlVeryHidden

End Sub

  Пример 1.6

Как вы можете видеть выше, я добавил оператор в начало кода перед началом любой из строк. Теперь запустите код и посмотрите, что произойдет.

VBA при ошибке Возобновление следующего примера 1.7

Теперь я нахожусь в строке, которая ранее выдавала ошибку, нажмите клавишу F8 и посмотрите, что произойдет.

Пример 1.8

Я перешел к следующей строке кода, не показав никакой ошибки из-за оператора, который мы добавили вверху, который является оператором VBA «При ошибке возобновить следующий».

Пример #2

Теперь мы посмотрим, как использовать это утверждение, еще на одном примере. Посмотрите на приведенную ниже структуру данных для этого примера.

VBA при ошибке Возобновить следующий пример 2.0.1

У нас есть две таблицы над первой таблицей, в которых есть Emp Name и данные о зарплате во второй таблице, и у нас есть только Emp Name, поэтому с помощью VLOOKUP нам нужно получить данные о зарплате из левой таблицы.

Ниже приведен код, который я написал для получения деталей.

Код:

Sub On_Error1()

  Dim k As Long

  For k = 2 To 8
   Cells(k, 6).Value = WorksheetFunction.VLookup(Cells(k, 5), Range("A:B"), 2, 0)
  Next k

End Sub

Пример 2.1

Теперь запустите код построчно и посмотрите, что произойдет.

VBA при ошибке Возобновление следующего примера 2.2
Пример 2.3

После запуска кода первой ячейки мы получили результат для первого сотрудника. Повторите то же самое для второго сотрудника.

VBA при ошибке Возобновление следующего примера 2.4

На этот раз мы получили сообщение об ошибке. Давайте посмотрим на имя второго сотрудника в таблице.

  Пример 2.5

Имя второго сотрудника — «Гаятри», но его нет в первой таблице, поэтому Функция ВПР VBAФункция ВПР в VBA аналогична функции ВПР на листе, а метод использования ВПР в VBA — через приложение. Рабочий лист методаФункциячитать далее не возвращает ошибку «#Н/Д», когда функция ВПР не находит искомое значение в таблице; скорее, это дает вышеуказанное сообщение об ошибке.

Наша цель состоит в том, что если имя сотрудника не найдено в таблице, нам нужна пустая ячейка для этого сотрудника, мы игнорируем ошибку и выдаем результаты для остальных имен.

Нам нужно добавить оператор «При ошибке возобновить дальше» внутри цикла.

Код:

Sub On_Error1()

  Dim k As Long

  For k = 2 To 8
   On Error Resume Next
   Cells(k, 6).Value = WorksheetFunction.VLookup(Cells(k, 5), Range("A:B"), 2, 0)
  Next k

End Sub

VBA при ошибке Возобновление следующего примера 2.6

Теперь запустите код и посмотрите результат.

  Пример 2.7

Два имени сотрудника, “Гаятри и Каранвир,» нет в списке, поэтому эти коды строк, должно быть, столкнулись с ошибкой, так как мы добавили оператор обработчика ошибок «При ошибке Возобновить Далее” он проигнорировал эту строку кода и возобновил работу для следующего сотрудника.

Что нужно помнить здесь

  • «On Error Resume Next» — это оператор обработчика ошибок, когда нам нужно игнорировать известную ошибку.
  • Если вы хотите игнорировать сообщение об ошибке только для определенного набора кода, закройте следующий оператор при ошибке, добавив «При ошибке Перейти к 0» утверждение.

УЗНАТЬ БОЛЬШЕ >>

Post Views: 660

На чтение 25 мин. Просмотров 13.7k.

VBA Error Handling

Эта статья содержит полное руководство по обработке ошибок VBA. Если вы ищете краткое резюме, посмотрите таблицу быстрого руководства в первом разделе.

Если вы ищете конкретную тему по обработке ошибок VBA, ознакомьтесь с приведенным ниже содержанием.

Если вы новичок в VBA, то вы можете прочитать пост от начала до конца, так как он выложен в логическом порядке.

Содержание

  1. Краткое руководство по обработке ошибок
  2. Введение
  3. Ошибки VBA
  4. Заявление об ошибке
  5. Err объект
  6. Логирование
  7. Другие элементы, связанные с ошибками
  8. Простая стратегия обработки ошибок
  9. Полная стратегия обработки ошибок
  10. Обработка ошибок в двух словах

Краткое руководство по обработке ошибок

Пункт Описание
On Error Goto 0 При возникновении ошибки код останавливается и отображает
ошибку.
On Error Resume Next Игнорирует ошибку и
продолжает.
On Error Goto [Label] Переход к определенной метке при возникновении ошибки.
Это позволяет нам справиться
с ошибкой.
Err Object При возникновении ошибки
информация об ошибке
сохраняется здесь.
Err.Number Номер ошибки.
(Полезно, только если вам
нужно проверить, произошла ли конкретная ошибка.)
Err.Description Содержит текст ошибки.
Err.Source Вы можете заполнить это, когда используете Err.Raise.
Err.Raise Функция, которая позволяет
генерировать вашу собственную ошибку.
Error Function Возвращает текст ошибки из
номера ошибки.
Вышло из употребления.
Error Statement Имитирует ошибку. Вместо этого используйте Err.Raise.

Введение

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

Если мы считаем, что ошибка может произойти в какой-то
момент, рекомендуется написать специальный код для обработки ошибки, если она
возникнет, и устранить ее.

Для всех остальных ошибок мы используем общий код для их
устранения. Это где оператор обработки ошибок VBA вступает в игру. Они
позволяют нашему приложению корректно обрабатывать любые ошибки, которые мы не
ожидали.

Чтобы понять обработку ошибок, мы должны сначала понять
различные типы ошибок в VBA.

VBA Error Handling

Ошибки VBA

В VBA есть три типа ошибок

  1. Синтаксис
  2. Компиляция
  3. Время выполнения

Мы используем обработку ошибок для устранения ошибок во
время выполнения. Давайте посмотрим на каждый из этих типов ошибок, чтобы было
ясно, что такое ошибка во время выполнения.

Синтаксические ошибки

Если вы использовали VBA в течение какого-то времени, вы
увидите синтаксическую ошибку. Когда вы набираете строку и нажимаете return,
VBA оценивает синтаксис и, если он неверен, выдает сообщение об ошибке.

Например, если вы введете If и забудете ключевое слово Then,
VBA отобразит следующее сообщение об ошибке.

VBA Error Handling

Некоторые примеры синтаксических ошибок

' then отсутствует
If a > b

' не хватает = после i
For i 2 To 7

' отсутствует правая скобка
b = left("АБВГ",1

Синтаксические ошибки относятся только к одной строке. Они
возникают, когда синтаксис одной строки неверен.

Примечание. Диалоговое окно «Ошибка синтаксиса» можно отключить, выбрав «Сервис» -> «Параметры» и отметив «Автосинтаксическая проверка». Строка по-прежнему будет отображаться красным цветом в случае ошибки, но диалоговое окно не появится.

Ошибки компиляции

Ошибки компиляции происходят более чем в одной строке.
Синтаксис в одной строке правильный, но неверный, если учесть весь код проекта.

Примеры ошибок компиляции:

  • Оператор If без соответствующего оператора End If
  • For без Next
  •  Select без End Select
  • Вызов Sub или Function, которые не существуют
  • Вызов Sub или Function с неверными параметрами
  • Присвоение Sub или Function того же имени, что и для модуля
  • Переменные не объявлены (Option Explicit должен присутствовать в верхней части модуля)

На следующем снимке экрана показана ошибка компиляции,
которая возникает, когда цикл For не имеет соответствующего оператора Next.

VBA Error Handling

Использование Debug-> Compile

Чтобы найти ошибки компиляции, мы используем Debug->
Compile VBA Project из меню Visual Basic.

Когда вы выбираете Debug-> Compile, VBA отображает первую
обнаруженную ошибку.

Когда эта ошибка исправлена, вы можете снова запустить
Compile, и VBA найдет следующую ошибку.

Debug-> Compile также будет включать синтаксические
ошибки в поиск, что очень полезно.

Если ошибок не осталось и вы запускаете Debug-> Compile,
может показаться, что ничего не произошло. Однако «Компиляция» будет недоступна
в меню «Отладка». Это означает, что ваше приложение не имеет ошибок компиляции
в текущий момент.

Debug->Compile Error Summary

Debug-> Compile находит ошибки компиляции (проекта).

Он также найдет синтаксические ошибки.

Он находит одну ошибку каждый раз, когда вы ее используете.

Если нет ошибок компиляции, оставленная опция Компиляция
будет отображаться серым цветом в меню.

Debug-> Compile Usage

Вы должны всегда использовать Debug-> Compile, прежде чем
запускать свой код. Это гарантирует, что ваш код не будет иметь ошибок
компиляции при запуске.

Если вы не запускаете Debug-> Compile, то VBA может
обнаружить ошибки компиляции при запуске. Их не следует путать с ошибками
времени выполнения.

Ошибки во время выполнения

Ошибки во время выполнения возникают, когда ваше приложение
работает. Обычно они находятся вне вашего контроля, но могут быть вызваны
ошибками в вашем коде.

VBA Error Handling

Например, представьте, что ваше приложение читает из внешней
рабочей книги. Если этот файл будет удален, то VBA отобразит ошибку, когда ваш
код попытается открыть его.

Другие примеры ошибок времени выполнения

  • база данных недоступна
  • пользователь вводит неверные данные
  • ячейка, содержащая текст вместо числа

Как мы уже видели, целью обработки ошибок является обработка
ошибок времени выполнения, когда они возникают.

Ожидаемые и неожиданные ошибки

Когда мы думаем, что может произойти ошибка во время
выполнения, мы помещаем код на место для ее обработки. Например, мы обычно
помещаем код на место, чтобы иметь дело с файлом, который не найден.

Следующий код проверяет, существует ли файл, прежде чем он
пытается его открыть. Если файл не существует, отображается сообщение, удобное
для пользователя, и код выходит из подпрограммы.

Sub OtkritFail()
    
    Dim sFile As String
    sFile = "C:ДокументыОтчет.xlsx"
    
    ' Используйте Dir, чтобы проверить, существует ли файл
    If Dir(sFile) = "" Then
        ' если файл не существует, отобразить сообщение
        MsgBox "Файл не найден" & sFile
        Exit Sub
    End If
    
    ' Код достигнет только если файл существует
    Workbooks.Open sFile
    
End Sub

Когда мы думаем, что в какой-то момент может произойти
ошибка, рекомендуется добавить код для обработки ситуации. Мы обычно называем
эти ошибки ожидаемыми.

Если у нас нет специального кода для обработки ошибки, это
считается неожиданной ошибкой. Мы используем операторы обработки ошибок VBA для
обработки непредвиденных ошибок.

Ошибки времени выполнения, которые не являются ошибками VBA

Прежде чем мы рассмотрим VBA Handling, мы должны упомянуть
один тип ошибок. Некоторые ошибки во время выполнения не рассматриваются как
ошибки VBA, а только пользователем.

Позвольте мне объяснить это на примере. Представьте, что у
вас есть приложение, которое требует, чтобы вы добавили значения в переменные a
и b

Допустим, вы по ошибке используете звездочку вместо знака
плюс

Это не ошибка VBA. Ваш синтаксис кода является совершенно
законным. Однако, с вашей точки зрения, это ошибка.

Эти ошибки не могут быть обработаны с помощью обработки ошибок, поскольку они, очевидно, не будут генерировать никаких ошибок. Вы можете справиться с этими ошибками, используя Unit Testing and Assertions.

Заявление об ошибке

Как мы видели, есть два способа обработки ошибок во время
выполнения

  1. Ожидаемые ошибки — напишите конкретный код для
    их обработки.
  2. Неожиданные ошибки — используйте операторы
    обработки ошибок VBA для их обработки.

Оператор VBA On Error используется для обработки ошибок.
Этот оператор выполняет некоторые действия при возникновении ошибки во время
выполнения.

Есть четыре различных способа использовать это утверждение

  1. On Error Goto 0 — код останавливается на строке с ошибкой и отображает сообщение.
  2. On Error Resume Next — код перемещается на следующую строку. Сообщение об ошибке не отображается.
  3. On Error Goto [label] — код перемещается на определенную строку или метку. Сообщение об ошибке не отображается. Это тот, который мы используем для обработки ошибок.
  4. On Error Goto -1 — очищает текущую ошибку.

Давайте посмотрим на каждое из этих утверждений по очереди.

On Error Goto 0

Это поведение по умолчанию VBA. Другими словами, если вы не
используете On Error, это поведение вы увидите.

При возникновении ошибки VBA останавливается на строке с
ошибкой и отображает сообщение об ошибке. Приложение требует вмешательства
пользователя с кодом, прежде чем оно сможет продолжить. Это может быть
исправление ошибки или перезапуск приложения. В этом случае обработка ошибок не
происходит.

Давайте посмотрим на пример. В следующем коде мы не
использовали строку On Error, поэтому VBA будет использовать поведение On Error
Goto 0 по умолчанию.

Sub IspDefault()

    Dim x As Long, y As Long
    
    x = 6
    y = 6 / 0
    x = 7

End Sub

Вторая строка присваивания приводит к ошибке деления на ноль. Когда мы запустим этот код, мы получим сообщение об ошибке, показанное на скриншоте ниже.

VBA Error Handling

Когда появляется ошибка, вы можете выбрать End или Debug

Если вы выберете Конец, то приложение просто остановится.

Если вы выберете Отладить, приложение остановится на строке
ошибки, как показано на скриншоте ниже.

VBA Error Handling

Это нормально, когда вы пишете код VBA, поскольку он
показывает вам точную строку с ошибкой.

Это поведение не подходит для приложения, которое вы
передаете пользователю. Эти ошибки выглядят непрофессионально и делают
приложение нестабильным.

Подобная ошибка, по сути, приводит к сбою приложения.
Пользователь не может продолжить работу без перезапуска приложения. Они могут
вообще не использовать его, пока вы не исправите для них ошибку.

Используя On Error Goto [label], мы можем дать пользователю
более контролируемое сообщение об ошибке. Это также предотвращает остановку
приложения. Мы можем заставить приложение работать предопределенным образом.

On Error Resume Next

Использование On Error Resume Next указывает VBA
игнорировать ошибку и продолжать работу.

Есть конкретные случаи, когда это полезно. Большую часть
времени вы должны избегать его использования.

Если мы добавим Resume Next к нашему примеру Sub, то VBA
проигнорирует ошибку деления на ноль

Sub UsingResumeNext()

    On Error Resume Next
    
    Dim x As Long, y As Long
    
    x = 6
    y = 6 / 0
    x = 7

End Sub

Это не очень хорошая идея, чтобы сделать это. Если вы
игнорируете ошибку, то поведение может быть непредсказуемым. Ошибка может
повлиять на приложение несколькими способами. Вы можете получить неверные
данные. Проблема в том, что вы не знаете, что что-то пошло не так, потому что
вы подавили ошибку.

Приведенный ниже код является примером использования Resume
Next.

Sub OtprSoobsch()

   On Error Resume Next
   
    ' Требуется ссылка:
    ' Библиотека объектов Microsoft Outlook 15.0
    Dim Outlook As Outlook.Application
    Set Outlook = New Outlook.Application

    If Outlook Is Nothing Then
        MsgBox " Не удается создать сеанс Microsoft Outlook." _
                   & " Письмо не будет отправлено."
        Exit Sub
    End If
    
End Sub

В этом коде мы проверяем, доступен ли Microsoft Outlook на компьютере. Все,
что мы хотим знать — это доступно или нет. Нас не интересует конкретная ошибка.

В приведенном выше коде мы продолжаем, если есть ошибка.
Затем в следующей строке мы проверяем значение переменной Outlook. Если произошла ошибка, тогда
значение этой переменной будет установлено равным Nothing.

Это пример того, когда Резюме может быть полезным. Дело в
том, что, хотя мы используем Resume,
мы все равно проверяем наличие ошибки. Подавляющее большинство времени вам не
нужно будет использовать Resume.

On Error Goto [label]

Вот как мы используем обработку ошибок в VBA. Это эквивалент функциональности Try and Catch, которую вы видите на
таких языках, как C # и
Java.

При возникновении ошибки вы отправляете ошибку на
определенный ярлык. Обычно это внизу саба.

Давайте применим это к подводной лодке, которую мы
использовали

Sub IspGotoLine()

    On Error Goto eh
    
    Dim x As Long, y As Long
    
    x = 6
    y = 6 / 0
    x = 7
    
Done:
    Exit Sub
eh:
    MsgBox "Произошла следующая ошибка: " & Err.Description
End Sub

Снимок экрана ниже показывает, что происходит при возникновении ошибки.

VBA Error Handling

VBA переходит на метку eh, потому что мы указали это в
строке «Перейти к ошибке».

Примечание 1: Метка, которую мы используем в операторе On… Goto, должна быть в текущей Sub / Function. Если нет, вы получите ошибку компиляции.

Примечание 2: Когда возникает ошибка при использовании On Error Goto [label], обработка ошибок возвращается к поведению по умолчанию, т.е. код остановится на строке с ошибкой и отобразит сообщение об ошибке. См. Следующий раздел для получения дополнительной информации об этом.

On Error Goto -1

Это утверждение отличается от других трех. Он используется
для очистки текущей ошибки, а не для настройки конкретного поведения.

При возникновении ошибки с помощью функции On Error Goto [label] поведение обработки ошибки возвращается к поведению по умолчанию, т.е. On Error Goto 0 . Это означает, что если произойдет другая ошибка, код остановится на текущей строке.

Это поведение относится только к текущей подпрограмме. Как
только мы выйдем из саба, ошибка будет очищена автоматически.

Посмотрите на код ниже. Первая ошибка приведет к переходу
кода на метку eh. Вторая ошибка остановится на строке с ошибкой 1034.

Sub DveOshibki()

    On Error Goto eh
        
    ' генерировать ошибку «Несоответствие типов»
    Error (13)

Done:
    Exit Sub
eh:
    ' генерировать «определенную приложением» ошибку
    Error (1034)
End Sub

Если мы добавим дальнейшую обработку ошибок, она не будет
работать, поскольку ловушка ошибок не была очищена.

В коде ниже мы добавили строку

после того как мы поймаем первую ошибку.

Это не имеет никакого эффекта, так как ошибка не была
очищена. Другими словами, код остановится на строке с ошибкой и отобразит
сообщение.

Sub DveOshibki()

    On Error Goto eh
        
    ' генерировать ошибку «Несоответствие типов»
    Error (13)

Done:
    Exit Sub
eh:
    On Error Goto eh_other
    ' генерировать «определенную приложением» ошибку
    Error (1034)
Exit Sub
eh_other:
    Debug.Print "ehother " & Err.Description
End Sub

Для устранения ошибки мы используем On Error Goto -1.
Думайте об этом как об установке ловушки для мыши. Когда ловушка сработает, вам
нужно установить ее снова.

В приведенном ниже коде мы добавляем эту строку, и вторая
ошибка теперь приведет к переходу кода на метку eh_other.

Sub DveOshibki()

    On Error Goto eh
        
    ' генерировать ошибку «Несоответствие типов»
    Error (13)

Done:
    Exit Sub
eh:
    ' явная ошибка
    On Error Goto -1
    
    On Error Goto eh_other
    ' генерировать «определенную приложением» ошибку
    Error (1034)
Exit Sub
eh_other:
    Debug.Print "ehother " & Err.Description
End Sub

Примечание 1. Вероятно, в редких случаях полезно использовать On Error Goto -1. Мне лично никогда не приходилось пользоваться этой линией. Помните, что как только вы выйдете из Sub, ошибка все равно будет очищена.

Примечание 2. у объекта Err есть член Clear. Использование Clear очищает текст и цифры в объекте Err, но НЕ сбрасывает ошибку.

Использование On Error

Как мы уже видели, VBA будет делать одну из трех вещей при возникновении ошибки:

  • Остановитесь и отобразите ошибку.
  • Игнорируйте ошибку и продолжайте.
  • Перейти к определенной строке.

VBA всегда будет настроен на одно из этих действий. Когда вы
используете On Error, VBA изменит ваше поведение и забудет о любом предыдущем.

В следующем подпункте VBA изменяет поведение ошибки каждый
раз, когда мы используем оператор On Error

Sub ErrorSostoyaniya()

    Dim x As Long
    
    ' Перейти на этикетке, если ошибка
    On Error Goto eh
    
    ' это проигнорирует ошибку в следующей строке
    On Error Resume Next
    x = 1 / 0
    
    ' это отобразит сообщение об ошибке в следующей строке
    On Error Goto 0
    x = 1 / 0
  
Done:  
   Exit Sub
eh:
    Debug.Print Err.Description
End Sub

Err объект

При возникновении ошибки вы можете просмотреть детали
ошибки, используя объект Err.

При возникновении ошибки времени выполнения VBA
автоматически заполняет объект Err деталями.

Приведенный ниже код выведет «Error Number: 13 Type
Mismatch», которое возникает, когда мы пытаемся поместить строковое значение в
длинное целое число.

Sub IspErr()

    On Error Goto eh
    
    Dim total As Long
    total = "aa"

Done:
    Exit Sub
eh:
    Debug.Print "Номер ошибки: " & Err.Number _
            & " " & Err.Description
End Sub

Err.Description предоставляет подробную информацию об ошибке, которая происходит. Это текст, который вы обычно видите, когда возникает ошибка, например, «Несоответствие типов»

Err.Number — это идентификационный номер ошибки, например, номер ошибки для «Несоответствие типов» — 13. Единственное время, когда вам действительно нужно это, если вы проверяете, что произошла конкретная ошибка, и это необходимо только в редких случаях.

Свойство Err.Source кажется отличной идеей, но оно не работает при ошибке VBA. Источник вернет имя проекта, которое вряд ли сузит место возникновения ошибки. Однако, если вы создаете ошибку с помощью Err.Raise, вы можете установить источник самостоятельно, и это может быть очень полезно.

Получение номера строки

Функция Erl используется для возврата номера строки, где
произошла ошибка.

Это часто вызывает путаницу. В следующем коде Erl вернет ноль.

Sub IspErr()

    On Error Goto eh
    
    Dim val As Long
    val = "aa"

Done:
    Exit Sub
eh:
    Debug.Print Erl
End Sub

Это потому, что нет номеров строк. Большинство людей не
понимают этого, но VBA позволяет вам иметь номера строк.

Если мы изменим подпрограмму, указав номер строки, она теперь выведет 20.

Sub IspErr()

10        On Error Goto eh
          
          Dim val As Long
20        val = "aa"

Done:
30        Exit Sub
eh:
40        Debug.Print Erl
End Sub

Добавление номеров строк в код вручную затруднительно.
Однако есть инструменты, которые позволят вам легко добавлять и удалять номера
строк в подпрограмме.

Когда вы закончите работу над проектом и передадите его
пользователю, в этот момент может быть полезно добавить номера строк. Если вы
используете стратегию обработки ошибок в последнем разделе этого поста, то VBA
сообщит строку, где произошла ошибка.

Использование Err.Raise

Err.Raise позволяет нам создавать ошибки. Мы можем
использовать его для создания пользовательских ошибок для нашего приложения,
что очень полезно. Это эквивалент оператора Throw в Java C #.

Формат следующий

Err.Raise [error number], [error source], [error description]

Давайте посмотрим на простой пример. Представьте, что мы
хотим убедиться, что в ячейке есть запись длиной 5 символов. Мы могли бы иметь конкретное сообщение для
этого

Public Const ERROR_INVALID_DATA As Long = vbObjectError + 513

Sub ReadWorksheet()

    On Error Goto eh
    
    If Len(Sheet1.Range("A1")) <> 5 Then
        Err.Raise ERROR_INVALID_DATA, "ReadWorksheet" _
            , "Значение в ячейке A1 должно иметь ровно 5 символов."
    End If
    
    ' продолжить, если ячейка имеет действительные данные
    Dim id As String
    id = Sheet1.Range("A1")
    

Done:
    Exit Sub
eh:
    ' Err.Raise отправит код сюда
    MsgBox " Обнаружена ошибка: " & Err.Description
End Sub

Когда мы создаем ошибку, используя Err.Raise, нам нужно присвоить ей номер. Мы можем использовать любое
число от 513 до 65535 для нашей ошибки. Мы должны использовать vbObjectError с номером,
например

Err.Raise vbObjectError + 513

Использование Err.Clear

Err.Clear используется для очистки текста и чисел из объекта
Err.Object. Другими словами, он очищает описание и номер.

Редко вам понадобится его использовать, но давайте
рассмотрим пример, где вы могли бы.

В приведенном ниже коде мы подсчитываем количество ошибок,
которые могут возникнуть. Для простоты мы генерируем ошибку для каждого
нечетного числа.

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

Sub IspErrClear()

    Dim count As Long, i As Long

    ' Продолжите, если ошибка, так как мы проверим номер ошибки
    On Error Resume Next
    
    For i = 0 To 9
        ' генерировать ошибку для каждого второго
        If i Mod 2 = 0 Then Error (13)
        
        ' Проверьте на ошибку
        If Err.Number <> 0 Then
            count = count + 1
            Err.Clear    ' Очистить Err, как только он считается
        End If
    Next

    Debug.Print " Количество ошибок было: " & count
End Sub

Примечание: Err.Clear сбрасывает текст и цифры в объекте ошибки, но не очищает ошибку — см. On Error Goto -1 для получения дополнительной информации об очистке фактической ошибки.

Логирование

Ведение журнала означает запись информации из вашего
приложения, когда оно запущено. При возникновении ошибки вы можете записать
детали в текстовый файл, чтобы у вас была запись об ошибке.

Код ниже показывает очень простую процедуру регистрации

Sub Logger(sType As String, sSource As String, sDetails As String)
    
    Dim sFilename As String
    sFilename = "C:templogging.txt"
    
    ' Архивный файл определенного размера
    If FileLen(sFilename) > 20000 Then
        FileCopy sFilename _
            , Replace(sFilename, ".txt", Format(Now, "ddmmyyyy hhmmss.txt"))
        Kill sFilename
    End If
    
    ' Откройте файл для записи
    Dim filenumber As Variant
    filenumber = FreeFile 
    Open sFilename For Append As #filenumber
    
    Print #filenumber, CStr(Now) & "," & sType & "," & sSource _
                                & "," & sDetails & "," & Application.UserName
    
    Close #filenumber
    
End Sub

Вы можете использовать это так:

' Создать уникальный номер ошибки
Public Const ERROR_DATA_MISSING As Long = vbObjectError + 514

Sub CreateReport()

    On Error Goto eh
    
    If Sheet1.Range("A1") = "" Then
       Err.Raise ERROR_DATA_MISSING, "CreateReport", "Данные отсутствуют в ячейке A1"
    End If

    ' другой код здесь
Done:
    Exit Sub
eh:
    Logger "Error", Err.Source, Err.Description
End Sub

Журнал не только для записи ошибок. Вы можете записывать
другую информацию во время работы приложения. При возникновении ошибки вы
можете проверить последовательность событий до того, как произошла ошибка.

Ниже приведен пример регистрации. То, как вы реализуете
журналирование, зависит от характера приложения и его полезности.

Sub ReadingData()
    
    Logger "Information", "ReadingData()", "Starting to read data."
       
    Dim coll As New Collection
    ' Read data
    Set coll = ReadData
    
    If coll.Count < 10 Then
        Logger "Warning", "ReadingData()", "Number of data items is low."
    End If
    Logger "Information", "ReadingData()", "Number of data items is " & coll.Count
    
    Logger "Information", "ReadingData()", "Finished reading data."

End Sub

Наличие большого количества информации при работе с ошибкой
может быть очень полезным. Часто пользователь может не дать вам точную информацию
об ошибке, которая произошла. Глядя на журнал, вы можете получить более точную
информацию об информации.

Другие элементы, связанные с ошибками

В этом разделе рассматриваются некоторые другие инструменты
обработки ошибок, которые есть в VBA. Эти элементы считаются устаревшими, но я
включил их, поскольку они могут существовать в устаревшем коде.

Функция ошибки

Функция Error используется для печати описания ошибки с
заданным номером ошибки. Он включен в VBA для обеспечения обратной
совместимости и не нужен, поскольку вместо него можно использовать описание
Err.Description.

Ниже приведены некоторые примеры

' Распечатать текст «Деление на ноль»
Debug.Print Error(11)
' Распечатать текст "Несоответствие типов"
Debug.Print Error(13)
' Распечатать текст "Файл не найден"
Debug.Print Error(53)

Заявление об ошибке

Заявление об ошибке позволяет имитировать ошибку. Он включен
в VBA для обратной совместимости. Вместо этого вы должны использовать
Err.Raise.

В следующем коде мы моделируем ошибку «Разделить на ноль».

Sub ZayavlObOshibke()

    On Error Goto eh
        
    ' Это создаст деление на ноль ошибок
    Error 11
    
    Exit Sub
eh:
    Debug.Print Err.Number, Err.Description
End Sub

Это утверждение включено в VBA для обратной совместимости.
Вместо этого вы должны использовать Err.Raise.

Простая стратегия обработки ошибок

Со всеми различными опциями вы можете быть озадачены тем,
как использовать обработку ошибок в VBA. В этом разделе я покажу вам, как
реализовать простую стратегию обработки ошибок, которую вы можете использовать
во всех своих приложениях.

Основная реализация

Это простой обзор нашей стратегии

  1. Поместите строку On Error Goto Label  в начале нашего верхнего Sub.
  2. Поместите Label у обработки ошибок в конце нашего верхнего
    Sub.
  3. Если происходит ожидаемая ошибка, обработайте ее и продолжайте.
  4. Если приложение не может продолжить работу, используйте Err.Raise для перехода к метке обработки ошибок.
  5. В случае непредвиденной ошибки код автоматически перейдет к метке обработки ошибок.

На следующем рисунке показан обзор того, как это выглядит

error-handling

Следующий код показывает простую реализацию этой стратегии

Public Const ERROR_NO_ACCOUNTS As Long = vbObjectError + 514

Sub BuildReport()

    On Error Goto eh
    
    ' Если ошибка в ReadAccounts, то перейти к ошибке
    ReadAccounts
    
    ' Сделай что-нибудь с кодом
    
Done:
    Exit Sub
eh:
    ' Все ошибки будут прыгать сюда
    MsgBox Err.Source & ": Произошла следующая ошибка  " & Err.Description
End Sub

Sub ReadAccounts()
    
    ' ОЖИДАЕМАЯ ОШИБКА - Может обрабатываться кодом
    ' Приложение может обрабатывать A1 равным нулю
    If Sheet1.Range("A1") = 0 Then
        Sheet1.Range("A1") = 1
    End If
    
    ' ОЖИДАЕМАЯ ОШИБКА - не может быть обработана кодом
    ' Приложение не может быть продолжено, если нет учетной записи
    If Dir("C:ДокументыОтчет.xlsx") = "" Then
        Err.Raise ERROR_NO_ACCOUNTS, "UsingErr" _
                , "There are no accounts present for this month."
    End If

    ' НЕОЖИДАННАЯ ОШИБКА - не может быть обработана кодом
    ' Если ячейка B3 содержит текст, мы получим ошибку несоответствия типов
    Dim total As Long
    total = Sheet1.Range("B3")
    
    
    ' продолжить и читать счета
    
End Sub

Это хороший способ реализации обработки ошибок, потому что

  • Нам не нужно добавлять код обработки ошибок в
    каждую подпрограмму.
  • Если возникает ошибка, то VBA корректно
    завершает работу приложения.

Полная стратегия обработки ошибок

Стратегия выше имеет один недостаток. Он не сообщает вам,
где произошла ошибка. VBA не наполняет Err.Source чем-либо полезным, поэтому мы
должны сделать это сами.

В этом разделе я собираюсь представить более полную
стратегию ошибок. Я написал два сабвуфера, которые выполняют всю тяжелую
работу, поэтому все, что вам нужно сделать, это добавить их в свой проект.

Целью этой стратегии является предоставление вам стека * и
номера строки в случае возникновения ошибки.

* Стек — это список вспомогательных функций, которые
использовались в данный момент при возникновении ошибки.

Это наша стратегия

  1. Разместите обработку ошибок во всех
    подпрограммах.
  2. Когда происходит ошибка, обработчик ошибок
    добавляет подробности к ошибке и вызывает ее снова.
  3. Когда ошибка достигает самой верхней
    подпрограммы, она отображается.

Мы просто «всплываем» из-за ошибки. Следующая диаграмма
показывает простое визуальное представление о том, что происходит, когда в Sub3
возникает ошибка

Error Handling – bubbling

Единственная грязная часть этого — правильное форматирование
строк. Я написал две подводные лодки, которые справляются с этим, поэтому он
позаботится о вас.

Это две вспомогательные подводные лодки

Option Explicit

Public Const MARKER As String = "NOT_TOPMOST"

' Вызывает ошибку и добавляет номер строки и имя текущей процедуры
Sub RaiseError(ByVal errorno As Long, ByVal src As String _
                , ByVal proc As String, ByVal desc As String, ByVal lineno As Long)
    
    Dim sLineNo As Long, sSource As String
    
    ' Если маркера нет, тогда RaiseError вызывается впервые.
    If Left(src, Len(MARKER)) <> MARKER Then

        ' Добавить номер строки ошибки, если она есть
        If lineno <> 0 Then
            sSource = vbCrLf & "Line no: " & lineno & " "
        End If
   
        ' Добавить маркер и процедуру к источнику
        sSource = MARKER & sSource & vbCrLf & proc
        
    Else
        ' Если ошибка уже возникла, просто добавьте имя процедуры
        sSource = src & vbCrLf & proc
    End If
    
    ' Если код останавливается здесь, убедитесь, что DisplayError находится в верхней части Sub
    Err.Raise errorno, sSource, desc
    
End Sub

' Отображает ошибку, когда она достигает самого верхнего sub
' Примечание: вы можете добавить вызов для входа из этого подпункта
Sub DisplayError(ByVal src As String, ByVal desc As String _
                    , ByVal sProcname As String)

    ' Удалить маркер
    src = Replace(src, MARKER, "")
    
    Dim sMsg As String
    sMsg = " Произошла следующая ошибка: " & vbCrLf & Err.Description _
                    & vbCrLf & vbCrLf & " Расположение ошибки: "
    
    sMsg = sMsg + src & vbCrLf & sProcname
    
    ' Показать сообщение
    MsgBox sMsg, Title:="Ошибка "
    
End Sub

Пример использования этой стратегии

Вот простое кодирование, которое использует эти Sub. В этой стратегии мы не размещаем какой-либо код в верхнем подпрограмме. Мы только вызываем подводные лодки.

Sub Topmost()

    On Error Goto EH
    
    Level1

Done:
    Exit Sub
EH:
    DisplayError Err.source, Err.Description, "Module1.Topmost"
End Sub

Sub Level1()

    On Error Goto EH
    
    Level2

Done:
    Exit Sub
EH:
   RaiseError Err.Number, Err.source, "Module1.Level1", Err.Description, Erl
End Sub

Sub Level2()

    On Error Goto EH
    
    ' Ошибка здесь
    Dim a As Long
    a = "7 / 0"

Done:
    Exit Sub
EH:
    RaiseError Err.Number, Err.source, "Module1.Level2", Err.Description, Erl
End Sub

Результат выглядит так

error handling output

Если в вашем проекте есть номера строк, результат будет содержать номер строки ошибки.

error handling output line

Примечание: вы можете получить следующую ошибку при использовании этого кода:

“Programmatic Access to Visual Basic Project is not trusted”

Чтобы решить эту проблему, выполните следующие действия.

  1. Перейдите в раздел «Разработчик» на ленте и
    нажмите «Macro Security», которая находится под кодом.
  2. Нажмите «Настройка макроса» в левом списке.
  3. Поставьте флажок в поле «Доверительный доступ к
    объектной модели проекта VBA».
  4. Нажмите Ok.

Обработка ошибок в двух словах

  • Обработка ошибок используется для обработки ошибок, возникающих во время работы приложения.
  • Вы пишете определенный код для обработки ожидаемых ошибок. Вы используете оператор обработки ошибок VBA
    On Error Goto [label] для отправки VBA на метку при возникновении непредвиденной ошибки.
  • Вы можете получить подробную информацию об ошибке из Err.Description.
  • Вы можете создать свою собственную ошибку, используя Err.Raise.
  • Использование одного оператора On Error в самой верхней подпрограмме перехватит все ошибки в подпрограммах, которые вызываются отсюда.
  • Если вы хотите записать имя Sub с ошибкой, вы можете обновить ошибку и сбросить ее.
  • Вы можете использовать журнал для записи информации о приложении, когда оно запущено.

Обработка ошибок в VBA Excel с помощью оператора On Error. Синтаксис выражений с оператором On Error. Пример кода с простым обработчиком ошибок.

On Error – это оператор, который используется для отслеживания ошибок во время исполнения кода VBA. При возникновении ошибки On Error передает информацию о ней в объект Err и включает программу обработки ошибок, начинающуюся с указанной строки.

В первую очередь, обработчик ошибок нужен для пользователей файлов Excel с кодами VBA. Любая ошибка приводит к прекращению выполнения программы, открытию редактора VBA с непонятным для пользователя сообщением или даже к полному зависанию приложения.

Обработчик ошибок позволяет завершить выполнение программы при возникновении ошибки и вывести сообщение пользователю с ее описанием.

Синтаксис выражений с On Error

Включает алгоритм обнаружения ошибок и, в случае возникновения ошибки, передает управление операторам обработчика ошибок с указанной в выражении строки. Stroka – это метка, после которой расположены операторы обработчика ошибок.

Включает алгоритм обнаружения ошибок и, в случае возникновения ошибки, передает управление оператору, следующему за оператором, вызвавшем ошибку.

Отключает любой включенный обработчик ошибок в текущей процедуре.

Простой обработчик ошибок

Шаблон простейшего обработчика ошибок:

Sub Primer()

On Error GoTo Stroka

    ‘Блок операторов процедуры

Exit Sub

Stroka:

    MsgBox «Произошла ошибка: « & Err.Description

End Sub

Оператор On Error GoTo размещается в начале процедуры, метка и обработчик ошибок – в конце процедуры. Название метки можно сменить на другое, в том числе на кириллице.

Оператор Exit Sub обеспечивает выход из процедуры, если блок операторов выполнен без ошибок. Для вывода описания ошибки используется свойство Description объекта Err.

Примеры обработки ошибок

Пример 1
Деление на ноль:

Sub Primer1()

On Error GoTo Инструкция

    Dim a As Double

    a = 45 / 0

Exit Sub

Instr:

    MsgBox «Произошла ошибка: « & Err.Description

End Sub

Результат выполнения кода VBA Excel с обработчиком ошибок:

Пример 2
Выход за границы диапазона:

Sub Primer2()

On Error GoTo Instr

    Dim myRange As Range

    Set myRange = Range(«A1:D4»).Offset(2)

Exit Sub

Instr:

    MsgBox «Произошла ошибка: « & Err.Description

End Sub

Результат выполнения кода VBA Excel с оператором On Error GoTo:

Пример использования выражений On Error Resume Next и On Error GoTo 0 смотрите в статье: Отбор уникальных значений с помощью Collection.

Содержание

  1. Оператор On Error
  2. Синтаксис
  3. Примечания
  4. Пример
  5. См. также
  6. Поддержка и обратная связь
  7. Оператор On Error (Visual Basic)
  8. Синтаксис
  9. Компоненты
  10. Комментарии
  11. Свойство Number
  12. Оператор Throw
  13. При следующей ошибке возобновление
  14. При ошибке GoTo 0
  15. При ошибке goTo -1
  16. Неисправляемые ошибки

Оператор On Error

Включает программу обработки ошибок и указывает местоположение этой программы в процедуре; также может использоваться для отключения программы обработки ошибок.

Синтаксис

On Error GoTo line
On Error Resume Next
On Error GoTo 0

Синтаксис оператора On Error может принимать любую из следующих форм:

Statement Описание
On Error GoTo line Включает процедуру обработки ошибок, которая начинается в строке, указанной в аргументе обязательной строки .

Аргумент line представляет собой любую метку строки или любой номер строки.

Если возникает ошибка во время запуска, управление ветвями для строки, что делает обработник ошибок активным.

Указанная строка должна быть в той же процедуре, что и оператор On Error; в противном случае происходит ошибка во время компиляции.

On Error Resume Next Указывает, что при ошибке во время выполнения управление переходит к заявлению сразу после утверждения, где произошла ошибка, и выполнение продолжается. Используйте эту форму вместо On Error GoTo при доступе к объектам.
On Error GoTo 0 Отключает любой включенный обработчик ошибок в текущей процедуре.

Примечания

Если оператор On Error не используется, любая случившаяся ошибка выполнения является неустранимой; то есть в этом случае отображается сообщение об ошибке и выполнение прекращается.

«Включенный» обработчик ошибок — это обработчик, включенный оператором On Error; «активный» обработчик — это включенный обработчик, который находится в процессе обработки ошибки. Если ошибка возникает при активном обработнике ошибок (между возникновением ошибки и резюме, выходом из подгруппы , функцией exit или exit Property ), обработник ошибки текущей процедуры не может справиться с ошибкой. Управление возвращается к вызывающей процедуре.

Если вызывающая процедура содержит включенный обработчик ошибок, он активируется для обработки ошибки. Если обработчик ошибок вызывающей процедуры также активный, управление передается обратно через предыдущие вызывающие процедуры до тех пор, пока не будет найден включенный, но неактивный обработчик. Если не удается найти неактивный включенный обработчик ошибок, ошибка является неустранимой в той точке, в которой она фактически произошла.

Каждый раз, когда обработчик ошибок передает управление обратно вызывающей процедуре, эта процедура становится текущей процедурой. После обработки ошибки обработчивем ошибки в любой процедуре, выполнение возобновляется в текущей процедуре в точке, указанной в заявлении Resume .

Процедура обработки ошибок не является процедурой Sub или Функцией . Это раздел кода, помеченный меткой строки или номером строки.

Процедуры обработки ошибок зависят от значения в свойстве Номер объекта Err для определения причины ошибки. Программа обработки ошибок должна проверить или сохранить соответствующие значения свойства в объекте Err, прежде чем может произойти любая другая ошибка или прежде чем будет вызвана процедура, которая может вызвать ошибку. Значения свойства в объекте Err отражают только самую последнюю ошибку. Сообщение об ошибке, связанное с Err.Number, содержится в Err.Description.

On Error Resume Next вызывает продолжение выполнения с оператора, сразу же следующего за оператором, вызвавшим ошибку выполнения, или с оператора, сразу же следующего за последним вызовом процедуры, содержащей оператор On Error Resume Next. Этот оператор разрешает продолжать выполнение несмотря на ошибку выполнения. Можно поместить программу обработки ошибок туда, где может произойти ошибка, вместо того чтобы переносить управление в другое местоположение в процедуре. Оператор On Error Resume Next становится неактивным, когда вызывается другая процедура, поэтому следует выполнять оператор On Error Resume Next в каждой вызываемой программе, если нужно обрабатывать внутренние ошибки в этой программе.

При обработке ошибок, возникающих при обращении к другим объектам, конструкция On Error Resume Next предпочтительнее, чем On Error GoTo. Проверка объекта Err после каждого взаимодействия с объектом позволяет устранить неоднозначность в плане того, к какому объекту обращался код. Вы можете точно определить, какой объект поместил код ошибки в свойство Err.Number, а также какой объект изначально сгенерировал ошибку (объект, указанный в свойстве Err.Source).

Оператор On Error GoTo 0 отключает обработку ошибок в текущей процедуре. Он не указывает строку 0 в качестве начала кода обработки ошибки, даже если процедура содержит строку с номером 0. Без оператора On Error GoTo 0 обработчик ошибок автоматически отключается, когда выполняется выход из процедуры.

Чтобы не допустить выполнения кода обработки ошибки, когда ошибка не произошла, поместите оператор Exit Sub, Exit Function или Exit Property непосредственно перед программой обработки ошибок, как показано в следующем фрагменте:

Здесь код обработки ошибок следует заявлению Exit Sub и предшествует заявлению End Sub , чтобы отделить его от потока процедуры. Код обработки ошибок может помещаться в любом месте процедуры.

Неперехваченные ошибки в объектах возвращаются в управляющее приложение, когда объект выполняется как исполняемый файл. В среде разработки неперехваченные ошибки только возвращаются в управляющее приложение, если заданы надлежащие параметры. Следующие сведения см. в документации ведущего приложения: какие параметры следует задать во время отладки, как задать эти параметры, может ли ведущее приложение создавать классы.

Если создается объект, имеющий доступ к другим объектам, следует попытаться обработать ошибки, передаваемые из этих объектов необработанными. Если вам не удается обрабатывать такие ошибки, сопоставьте код ошибки в Err.Number с одной из собственных ошибок и затем передайте их обратно вызывающей стороне объекта. Следует указать ошибку, добавив код ошибки в константу vbObjectError. Например, если код вашей ошибки — 1052, назначьте его следующим образом:

Системные ошибки во время вызовов Windows динамических библиотек ссылок (DLL) или ресурсов кода Macintosh не вызывают исключений и не могут быть заблокированы с помощью Visual Basic ошибок. При вызове функций DLL необходимо проверить каждое возвращаемого значения на успешность или сбой (в соответствии со спецификациями API), а в случае сбоя проверьте значение в свойстве lastDLLError объекта Err. Свойство LastDLLError всегда возвращает ноль в Macintosh.

Пример

В этом примере сначала используется оператор On Error GoTo для указания местоположения программы обработки ошибок в процедуре. В примере попытка удалить открытый файл генерирует ошибку номер 55. Ошибка обрабатывается в программе обработки ошибок, и затем управление возвращается к оператору, вызвавшему ошибку. Оператор On Error GoTo 0 выключает перехват ошибок.

Затем заявление On Error Resume Next используется для отсрочки улавливания ошибок, чтобы можно было точно знать контекст ошибки, порожденной следующим утверждением. Обратите внимание, что Err.Clear используется для очистки свойств объекта Err после обработки ошибки.

См. также

Поддержка и обратная связь

Есть вопросы или отзывы, касающиеся Office VBA или этой статьи? Руководство по другим способам получения поддержки и отправки отзывов см. в статье Поддержка Office VBA и обратная связь.

Источник

Оператор On Error (Visual Basic)

Включает подпрограмму обработки ошибок и указывает расположение подпрограммы в процедуре; также можно использовать для отключения подпрограммы обработки ошибок. Оператор On Error используется в неструктурированной обработке ошибок и может использоваться вместо структурированной обработки исключений. Структурированная обработка исключений встроена в .NET, как правило, более эффективна и поэтому рекомендуется при обработке ошибок среды выполнения в приложении.

Без обработки ошибок или обработки исключений любая возникающая ошибка во время выполнения неустранима: отображается сообщение об ошибке и выполнение останавливается.

Ключевое Error слово также используется в инструкции error, которая поддерживается для обеспечения обратной совместимости.

Синтаксис

Компоненты

Термин Определение
GoTo Линии Включает подпрограмму обработки ошибок, которая начинается со строки, указанной в требуемом аргументе строки . Аргумент строки — это любая метка строки или номер строки. При возникновении ошибки во время выполнения управление ветвляется в указанную строку, делая обработчик ошибок активным. Указанная строка должна находиться в той же процедуре, что и On Error инструкция , иначе возникнет ошибка во время компиляции.
GoTo 0 Отключает включенный обработчик ошибок в текущей процедуре и сбрасывает его до Nothing .
GoTo -1 Отключает включенного исключения в текущей процедуре и сбрасывает его до Nothing .
Resume Next Указывает, что при возникновении ошибки во время выполнения управление переходит к инструкции сразу после инструкции, в которой произошла ошибка, и выполнение продолжается с этой точки. Используйте эту форму, а не On Error GoTo при доступе к объектам.

Комментарии

Мы рекомендуем по возможности использовать структурированную обработку исключений в коде, а не не неструктурированную обработку исключений и инструкцию On Error . Дополнительные сведения см. в разделе Оператор Try. Catch. Finally.

Обработчик ошибок «включен» — это обработчик, который включается оператором On Error . «Активный» обработчик ошибок — это включенный обработчик, который находится в процессе обработки ошибки.

Если ошибка возникает, когда обработчик ошибок активен (между возникновением ошибки и оператором Resume , Exit Sub , Exit Function или Exit Property ), обработчик ошибок текущей процедуры не сможет обработать ошибку. Элемент управления возвращается в вызывающую процедуру.

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

Каждый раз, когда обработчик ошибок передает управление вызывающей процедуре, эта процедура становится текущей процедурой. После обработки ошибки обработчиком ошибок в любой процедуре выполнение возобновляется в текущей процедуре в точке, назначенной оператором Resume .

Подпрограмма обработки ошибок не является процедурой Sub или процедурой Function . Это раздел кода, помеченный меткой строки или номером строки.

Свойство Number

Подпрограммы обработки ошибок используют значение в свойстве Number Err объекта для определения причины ошибки. Подпрограмма должна проверять или сохранять соответствующие значения свойств в объекте Err до возникновения любой другой ошибки или перед вызовом процедуры, которая может вызвать ошибку. Значения свойств в объекте Err отражают только самую последнюю ошибку. Сообщение об ошибке, связанное с Err.Number , содержится в Err.Description .

Оператор Throw

Ошибка, возникающая при Err.Raise использовании метода , задает для Exception свойства только что созданный экземпляр Exception класса . Для поддержки создания исключений производных типов исключений Throw в языке поддерживается оператор . Для этого требуется один параметр, который является экземпляром исключения, который должен быть создан. В следующем примере показано, как эти функции можно использовать с существующей поддержкой обработки исключений:

Обратите внимание, что On Error GoTo оператор перехватывает все ошибки, независимо от класса исключения.

При следующей ошибке возобновление

On Error Resume Next приводит к продолжению выполнения с оператором сразу после оператора, вызвавшего ошибку во время выполнения, или оператором сразу после последнего вызова процедуры, содержащей инструкцию On Error Resume Next . Эта инструкция позволяет продолжить выполнение, несмотря на ошибку во время выполнения. Вы можете поместить подпрограмму обработки ошибок в место возникновения ошибки, а не передавать управление в другое расположение в процедуре. Оператор On Error Resume Next становится неактивным при вызове другой процедуры, поэтому следует выполнить инструкцию в каждой On Error Resume Next из вызываемой подпрограммы, если требуется встроенная обработка ошибок в рамках этой процедуры.

Конструкция On Error Resume Next может быть предпочтительнее, чем On Error GoTo при обработке ошибок, создаваемых при доступе к другим объектам. Проверка Err после каждого взаимодействия с объектом устраняет неоднозначность относительно того, к какому объекту был доступ из кода. Вы можете быть уверены, какой объект поместил код ошибки в Err.Number , а также какой объект изначально создал ошибку (объект, указанный в Err.Source ).

При ошибке GoTo 0

On Error GoTo 0 отключает обработку ошибок в текущей процедуре. Строка 0 не указывается в качестве начала кода обработки ошибок, даже если процедура содержит строку с нумеровкой 0. On Error GoTo 0 Без оператора обработчик ошибок автоматически отключается при завершении процедуры.

При ошибке goTo -1

On Error GoTo -1 отключает исключение в текущей процедуре. Строка -1 не указывается в качестве начала кода обработки ошибок, даже если процедура содержит строку с нумеровкой -1. On Error GoTo -1 Без оператора исключение автоматически отключается при завершении процедуры.

Чтобы предотвратить выполнение кода обработки ошибок при отсутствии ошибки, поместите инструкцию Exit Sub , Exit Function или Exit Property непосредственно перед подпрограммой обработки ошибок, как показано в следующем фрагменте:

Здесь код обработки ошибок следует за оператором Exit Sub и предшествует оператору End Sub , чтобы отделить его от потока процедуры. Код обработки ошибок можно разместить в любом месте процедуры.

Неисправляемые ошибки

Необрезанные ошибки в объектах возвращаются управляющее приложение, когда объект выполняется как исполняемый файл. В среде разработки неиспространенные ошибки возвращаются в управляющее приложение, только если заданы правильные параметры. Сведения о том, какие параметры следует задать во время отладки, как их задать и может ли узел создавать классы, см. в документации ведущего приложения.

При создании объекта, который обращается к другим объектам, следует попытаться обработать все необработанные ошибки, которые они передают обратно. Если вы не можете, сопоставьте коды ошибок в Err.Number с одной из собственных ошибок, а затем передайте их обратно вызывающему объекту. Необходимо указать ошибку, добавив код ошибки в константу VbObjectError . Например, если код ошибки равен 1052, назначьте его следующим образом:

Системные ошибки во время вызовов библиотек динамической компоновки Windows (DLL) не вызывают исключений и не могут быть захвачены с помощью перехвата ошибок Visual Basic. При вызове функций DLL следует проверять каждое возвращаемое значение на успешность или сбой (в соответствии со спецификациями API), а в случае сбоя — значение в Err свойстве LastDLLError объекта .

Источник

5 / 5 / 0

Регистрация: 15.06.2015

Сообщений: 342

1

Продолжить выполнение макроса в случае ошибки

17.07.2019, 05:38. Показов 3926. Ответов 6


Здравствуйте! нужна ваша помощь. У меня есть макрос. он иногда выдаёт ошибку на любом участке. и происходит это не из за ошибки кода,а из за переполнения оперативной памяти или если 2-3 копии excel работают, с таким же макросом, то тоже может быть сбой и выскакивает то окно где написано END и DEBUG.
Мне нужно , что бы макрос в случае вот таких вот ситуаций продолжал работать методом повторного выполнения операции над которой и случилась ошибка(чтобы заново её выполнил). Я немного поискал в интернете и выяснил, что за это отвечает оператор Resume 0. Есть оператор Resume Next, который игнорирует ошибку и макрос продолжает работать со следующей операции. Но мне это не подойдёт. мне нужно именно, чтобы макрос заново с операции на которой случилась ошибка продолжил работать(т.е. выполнил её снова)
Только вот куда этот Resume 0 сувать? Хотелось бы чтобы поставить этот Resume 0 в начале всего кода макроса, и не париться. Но как это сделать?

__________________
Помощь в написании контрольных, курсовых и дипломных работ, диссертаций здесь



0



1778 / 1108 / 338

Регистрация: 11.07.2014

Сообщений: 3,910

17.07.2019, 06:14

2

Oleg395, не думаю, что ваши рассуждения по поводу ошибок справедливы. Памяти не хватает — и какая длина ваших массивов и характеристики компа? А когда работают копии экселя, вы думаете они следят друг за другом и, когда видят, что в другой версии работает такой же макрос, то начинают бастовать? Интересно как они это видят? Надо просто смотреть файл и искать ошибку или средства совместимости копий.

Добавлено через 4 минуты
а по поводу ошибки — есть такая конструкция On Error GoTo Metka, а эту метку поставить перед оператором, который нужно повторить



0



Oleg395

5 / 5 / 0

Регистрация: 15.06.2015

Сообщений: 342

17.07.2019, 07:40

 [ТС]

3

Burk, я же говорю ошибок никаких нет. Burk, Вы когда ни будь запускали 40 Excel? тогда лучше оставьте свои догадки при себе откуда могут браться глюки.
не думаю что On Error GoTo Metka это правильный оператор в моей ситуации.
и куда ваш оператор засовывать? часто глюк возникает перед: Sheets(Array(«2»)).Copy

макрос у меня очень простой. сохранение листа в файл:

Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
Sub Сохранение()
Application.ScreenUpdating = False
Dim Fname As String
    Sheets(Array("2")).Copy 
    With ActiveWorkbook  
 ActiveSheet.UsedRange.Value = ActiveSheet.UsedRange.Value
        Application.DisplayAlerts = False
        .SaveAs Filename:=ThisWorkbook.Path & "" & "1.xls", FileFormat:=56
        Application.ScreenUpdating = True
        'Application.DisplayAlerts = True
          End With
      ActiveWorkbook.Close
    End Sub



0



tmash

34 / 29 / 6

Регистрация: 21.08.2015

Сообщений: 116

18.07.2019, 22:57

4

Привет!

Пробовали строку

Visual Basic
1
Sheets(Array("2")).Copy

заменить на попроще, типа

Visual Basic
1
Sheets("Лист_Имя").Copy

?



0



5 / 5 / 0

Регистрация: 15.06.2015

Сообщений: 342

18.07.2019, 22:59

 [ТС]

5

tmash, пробовали.
я не об этом спрашиваю. не флудите. Я про оператор спрашивал.



0



5 / 5 / 0

Регистрация: 15.06.2015

Сообщений: 342

18.07.2019, 23:17

 [ТС]

7

tmash, интригу не создавайте и тем самым свою весомость. если что то знаете и есть желание помочь по существу, делайте, а не флудите.



0



Обработка ошибок

Если вы когда-нибудь учились водить автомобиль, то наверняка вспомните, что при первой посадке на водительское сиденье все внимание было приковано к трем деталям: рулю, педалям и рычагу переключения передач. Происходящее вне автомобиля уходило на второй план, так как вначале нужно было стронуться с места. По мере практики навыки вождения улучшались и эти три детали постепенно уходили на задний план. Как ни странно, но руль и рычаг переключения передач всегда оказывались там, куда вы не смотря протягивали руки, а ноги сами находили педали. Теперь все внимание стало занимать происходящее на дороге. Иными словами, вы стали опытным водителем.

В программировании все абсолютно также. Начинающие программисты больше обращают внимание на первые попавшиеся на глаза операторы, функции и другие элементы языка, а сам алгоритм уходит на задний план. Если программа скомпилировалась без ошибок, то это уже большое счастье, хотя это еще не означает, что программа работает правильно. По мере практики мышление программиста меняется, он начинает обращать внимание на мелочи, на форматирование программы, использует более эффективные алгоритмы и в результате всего этого допускает меньше ошибок. Подводя итоги, можно сказать, что начинающий программист просто пишет программу, а опытный программист пытается найти оптимальный алгоритм и предусмотреть поведение программы в различных ситациях. Однако, от ошибок никто не застрахован, поэтому очень важно знать как быстро найти ошибку.

Типы ошибок

Существуют три типа ошибок в программе:

  • синтаксические — это ошибки в имени оператора или подпрограммы, отсутствие закрывающей или открывающей кавычек и т. д., то есть ошибки в синтаксисе языка. Как правило, компилятор предупредит о наличии ошибки, а программа не будет выполняться совсем;
  • логические — это ошибки в логике работы программы, которые можно выявить только по результатам работы программы. Как правило, компилятор не предупреждает о наличии ошибки, а программа будет выполняться, так как не содержит синтаксических ошибок. Такие ошибки достаточно трудно выявить;
  • ошибки времени выполнения — это ошибки, которые возникают во время работы программы. В одних случаях ошибки времени выполнения являются следствием логических ошибок, а в других случаях причиной являются внешние события, например, нехватка оперативной памяти, отсутствие прав для записи в файл и др.

Инструкция On Error

Ошибки времени выполнения можно перехватывать внутри подпрограммы. Для этого используется инструкция On Error, которая имеет три формата:

  • On Error GoTo <Метка> — при возникновении ошибки управление передается инструкции, помеченной меткой <Метка>. Метка должна быть допустимым идентификатором, к которому предъявляются такие же требования как и к переменным. Внутри подпрограммы метка указывается в самом начале помечаемой строки и после метки ставится двоеточие. В качестве примера создадим функцию для деления двух целых чисел. Внутри функции предусмотрим обработку ошибки деления на 0:
Function Деление(x As Integer, y As Integer) As Double
   On Error GoTo ПриОшибке
   Деление = x / y
   Exit Function
ПриОшибке:
   Деление = 0
End Function

Если при вызове функции во втором параметре передать значение 0, то управление будет передано в строку, помеченную с помощью метки ПриОшибке. Обратите внимание на то, что метка расположена после инструкции Exit Function. В этом случае код после инструкции Exit Function будет выполнен только в том случае, если возникнет ошибка;

  • On Error Resume Next — при возникновении ошибки управление передается следующей инструкции;
  • On Error GoTo 0 — отключает перехват ошибок.

Если внутри подпрограммы не предусмотрен перехват ошибки, то при возникновении ошибки работа программы прерывается и выводится стандартное окно с описанием и несколькими кнопками: Continue (продолжить), End (завершить выполнение программы), Debug (перейти в режим отладки) и Help (вывод справки).

Инструкция Resume

Инструкция Resume позволяет указать куда следует переходить после обработки ошибки. Инструкция имеет несколько форматов:

  • Resume [0] — управление передается инструкции, вызвавшей ошибку;
  • Resume Next — управление передается инструкции, следующей за инструкцией, вызвавшей ошибку;
  • Resume <Метка> — управление передается инструкции, помеченной меткой <Метка>.

Если инструкция Resume не указана, то выполняется только код внутри обработчика ошибки и производится выход из подпрограммы.

Получение информации об ошибке и генерация ошибки

Вся информация о последней ошибке доступна через объект Err. Объект содержит следующие свойства:

  • Number — код ошибки, например, код 11 для ошибки деления на 0. Если ошибки не произошло, то свойство содержит значение 0;
  • Description — описание ошибки, например, строка "Division by zero" для ошибки деления на 0. Пример вывода кода и описания ошибки:
Debug.Print Err.Number; Err.Description
  • Source — название текущего проекта;
  • HelpFile — путь к файлу справки;
  • HelpContext — идентификатор раздела в справочном файле;
  • LastDLLError — системный код ошибки при работе с DLL.

Объект Err содержит следующие методы:

  • Clear() — очищает всю информацию о последней ошибке. Этот метод следует вызвать после успешной обработки ошибки. Информация об ошибке автоматически очищается при выходе из подпрограммы и ряде других случаев;
  • Raise() — позволяет сгенерировать ошибку в программе. Формат метода:
Raise Number[, Source][, Description][, HelpFile][, HelpContext]

В параметре Number указывается код генерируемой ошибки (целое число от 0 до 65 535). Коды от 0 до 512 зарезервированы под системные ошибки, а остальные коды можно использовать под пользовательские ошибки. Чтобы сгенерировать ошибку с пользовательским кодом необходимо сложить код с константой vbObjectError. Остальные параметры являются необязательными и полностью аналогичны одноименным свойствам объекта Err. Пример генерации и обработки пользовательской ошибки:

Sub ГенерацияОшибки()
   On Error GoTo ПриОшибке
   Err.Raise vbObjectError + 513
   Exit Sub
ПриОшибке:
   Debug.Print Err.Number; Err.Description
   ' -2147220991 Automation error
End Sub

Способы поиска ошибок в программе

В предыдущих разделах мы научились обрабатывать ошибки времени выполнения. Однако, наибольшее количество времени программист затрачивает на другой тип ошибок — логические ошибки. В этом случае программа компилируется без ошибок, но результат выполнения программы не соответствует ожидаемому результату. Ситуация еще более осложняется, когда неверный результат проявляется лишь периодически, а не постоянно. Инсценировать такую же ситуацию, чтобы получить этот же неверный результат, бывает крайне сложно и занимает очень много времени. В этом разделе мы рассмотрим лишь «дедовские» (но по прежнему актуальные) способы поиска ошибок, а современные способы отладки приложений, доступные в VBA, изучим в следующем разделе.

Первое, на что следует обратить внимание, — на объявления переменных. Например, рассмотрим простой пример:

Как вы думаете, какое значение отобразится в окне Immediate после выполнения этого кода? Думаете, что число 10? Не факт! Вот тут-то и кроется проблема не видная на первый взгляд. В первой инструкции присваивается значение переменной x, имя которой набрано на английской раскладке клавиатуры, а вот во второй инструкции выводится значение переменной x, имя которой набрано на русской раскладке клавиатуры. В результате значение присваивается одной переменной, а выводится значение другой переменной. Такие ситуации очень часто встречаются в программах на языке VBA, так как объявлять переменную не обязательно. Чтобы избежать такой ситуации следует обязательно объявлять переменные явным образом. Контроль за соблюдением этого правила можно возложить на компилятор, добавив в начале модуля следующую инструкцию:

При наличии инструкции компилятор производит проверку объявления всех переменных. Если переменная не была объявлена явным образом, то компилятор выведет сообщение об ошибке и выполнение программы будет остановлено. Таким образом, код должен выглядеть следующим образом:

Option Explicit
...
Dim x As Integer
x = 10
Debug.Print x ' 10

Далее следует обратить внимание на форматирование кода. Начинающие программисты обычно не обращают на это никакого внимания, считая этот процесс лишним. А на самом деле зря! Компилятору абсолютно все равно, разместите вы все инструкции на одной строке или выполните форматирование кода. Однако, при поиске ошибок форматирование кода позволит найти ошибку гораздо быстрее.

Перед всеми инструкциями внутри блока должно быть расположено одинаковое количество пробелов. Обычно используют три или четыре пробела. От применения символов табуляции лучше отказаться. Если все же используете, то не следует в одном файле совмещать и пробелы и табуляцию. Для вложенных блоков количество пробелов умножают на уровень вложенности. Если для блока первого уровня вложенности использовалось три пробела, то для блока второго уровня вложенности должно использоваться шесть пробелов, для третьего уровня — девять пробелов и т. д. Пример форматирования вложенных блоков приведен в листинге 11.1.

Dim Массив As Variant, i As Integer, j As Integer
Массив = Array(Array(0, 1), Array(2, 3), Array(4, 5))
For i = 0 To 2
   For j = 0 To 1
      Debug.Print Массив(i)(j)
   Next
Next

Длина одной строки не должна содержать более 80 символов. Если количество символов больше, то следует выполнить переход на новую строку. При этом продолжение смещается относительно основной инструкции на величину отступа или выравнивается по какому-либо элементу. Иначе приходится пользоваться горизонтальной полосой прокрутки, а это очень неудобно при поиске ошибок.

Если программа слишком большая, то следует задуматься о разделении программы на отдельные подпрограммы или классы, которые выполняют логически законченные действия. Помните, что отлаживать отдельную подпрограмму гораздо легче, чем «спагетти»-код. Причем прежде чем вставить подпрограмму (или класс) в основную программу ее следует протестировать в отдельном проекте, передавая подпрограмме различные значения и проверяя результат ее выполнения.

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

Причиной периодических ошибок чаще всего являются внешние данные. Например, если числа получаются от пользователя, а затем производится деление чисел, то вполне возможна ситуация, при которой пользователь введет число 0. Деление на ноль приведет к ошибке. Следовательно, все данные, которые поступают от пользователей, должны проверяться на соответствие допустимым значениям. Если данные не соответствуют, то нужно вывести сообщение об ошибке, а затем повторно запросить новое число или прервать выполнение всей программы. Кроме того, нужно обработать возможность того, что пользователь может ввести вовсе не число, а строку.

Метод Print() объекта Debug удобно использовать для вывода промежуточных значений. В этом случае значения переменных вначале выводятся в самом начале программы и производится проверка соответствия значений. Если значения соответствуют, то инструкция с методом Print() перемещается на следующую строку программы и опять производится проверка и т. д. Если значения не совпали, то ошибка возникает в инструкции, расположенной перед инструкцией с методом Print(). Если это пользовательская подпрограмма, то проверку значений производят внутри подпрограммы, каждый раз перемещая инструкцию с выводом значений. На одном из этих многочисленных этапов ошибка обычно обнаруживается. В больших программах можно логически догадаться о примерном расположении инструкции с ошибкой и начать поиск ошибки оттуда, а не с самого начала программы.

Инструкции для вывода промежуточных значений можно расставить уже при написании программы, не дожидаясь возникновения ошибки. В этом случае в начале программы объявляется константа с помощью инструкции #Const, а внутри программы производится проверка значения константы:

Проверить значение константы позволяет следующая конструкция:

#If MY_DEBUG Then
   ' Здесь размещаем инструкции вывода значений
#End If

Таким образом, меняя значение константы MY_DEBUG с 1 на 0, можно отлючать вывод всех промежуточных значений.

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

Прежде чем начать отладку необходимо пометить строки внутри программы с помощью точек останова. Для добавления точки останова делаем строку активной, а затем из меню Debug выбираем пункт Toggle Breakpoint. Слева от строки появится кружок, обозначающий точку останова. Добавить точку останова можно еще быстрее. Для этого достаточно щелкнуть слева от строки левой кнопкой мыши. Повторный щелчок позволяет удалить точку останова. Кроме того, для добавления или удаления точки отстанова можно воспользоваться клавишей <F9>. Чтобы удалить все точки останова следует из меню View выбрать пункт Clear All Breakpoints.

Когда точки останова расставлены можно начать отладку. Для этого запускаем программу на выполнение обычным способом. При достижении точки останова выполнение программы прерывается и отладчик ожидает дальнейших действий программиста. Инструкция, которая будет выполняться на следующем шаге, помечается желтой стрелкой слева от строки.

В режиме прерывания можно посмотреть значения различных переменных в окне Locals. Если окно не отображается, то отобразить его можно выбрав в меню View пункт Locals Window. Посмотреть значение переменной можно также если навести указатель мыши на переменную. Значение переменной отобразится во всплывающей подсказке.

При отладке можно контролировать значения отдельных переменных, а не всех сразу. Для этого следует выделить название переменной и из меню Debug выбрать пункт Add Watch. Можно также выделить название переменной и из контектного меню выбрать пункт Add Watch. В открывшемся окне устанавливаем флажок Watch Expression и нажимаем кнопку OK. Значение переменной будет отображаться в окне Watches. Чтобы отобразить окно Watches из меню View выбираем пункт Watch Window. Чтобы отменить отслеживание нужно выделить строку в окне Watches и нажать клавишу <Delete>.

Для пошагового выполнения программы предназначены следующие пункты в меню Debug или соответствующие кнопки на панели инструментов Debug (View | Toolbars | Debug):

  • Step Into (клавиша <F8>) — выполняет переход к следующей инструкции;
  • Step Over — выполняет одну инструкцию. Если в этой инструкции производится вызов подпрограммы, то подпрограмма выполняется за один шаг и отладчик переходит в режим ожидания после выхода из подпрограммы;
  • Step Out — при заходе в подпрограмму этот пункт позволяет выполнить подпрограмму за один шаг и выйти из нее. Отладчик переходит в режим прерывания после выхода из подпрограммы;
  • Run To Cursor — выполняет переход к инструкции, в которой расположен курсор.

Если необходимо посмотреть последовательность вызова подпрограмм, то следует открыть окно Call Stack, выбрав в меню View пункт Call Stack.

Подача звукового сигнала

При возникновении ошибки или при неправильном вводе данных имеет смысл привлечь внимание пользователя звуковым сигналом. Сгенерировать звуковой сигнал позволяет инструкция Beep. Пример:

Dim Результат
Beep
Результат = InputBox("Необходимо ввести значение")

Visual Basic for Applications (VBA)
Статьи по Visual Basic for Applications (VBA)

0 0 голоса
Рейтинг статьи
Подписаться
Уведомить о
guest

0 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии

А вот еще интересные материалы:

  • Яшка сломя голову остановился исправьте ошибки
  • Ясность цели позволяет целеустремленно добиваться намеченного исправьте ошибки
  • Ясность цели позволяет целеустремленно добиваться намеченного где ошибка
  • Продолжительный период лексическая ошибка
  • Продолжительность процесса плавки длится несколько часов тип ошибки