На чтение 25 мин. Просмотров 17.7k.
Эта статья содержит полное руководство по обработке ошибок VBA. Если вы ищете краткое резюме, посмотрите таблицу быстрого руководства в первом разделе.
Если вы ищете конкретную тему по обработке ошибок VBA, ознакомьтесь с приведенным ниже содержанием.
Если вы новичок в VBA, то вы можете прочитать пост от начала до конца, так как он выложен в логическом порядке.
Содержание
- Краткое руководство по обработке ошибок
- Введение
- Ошибки VBA
- Заявление об ошибке
- Err объект
- Логирование
- Другие элементы, связанные с ошибками
- Простая стратегия обработки ошибок
- Полная стратегия обработки ошибок
- Обработка ошибок в двух словах
Краткое руководство по обработке ошибок
Пункт | Описание |
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
В VBA есть три типа ошибок
- Синтаксис
- Компиляция
- Время выполнения
Мы используем обработку ошибок для устранения ошибок во
время выполнения. Давайте посмотрим на каждый из этих типов ошибок, чтобы было
ясно, что такое ошибка во время выполнения.
Синтаксические ошибки
Если вы использовали VBA в течение какого-то времени, вы
увидите синтаксическую ошибку. Когда вы набираете строку и нажимаете return,
VBA оценивает синтаксис и, если он неверен, выдает сообщение об ошибке.
Например, если вы введете If и забудете ключевое слово Then,
VBA отобразит следующее сообщение об ошибке.
Некоторые примеры синтаксических ошибок
' 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.
Использование 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 отобразит ошибку, когда ваш
код попытается открыть его.
Другие примеры ошибок времени выполнения
- база данных недоступна
- пользователь вводит неверные данные
- ячейка, содержащая текст вместо числа
Как мы уже видели, целью обработки ошибок является обработка
ошибок времени выполнения, когда они возникают.
Ожидаемые и неожиданные ошибки
Когда мы думаем, что может произойти ошибка во время
выполнения, мы помещаем код на место для ее обработки. Например, мы обычно
помещаем код на место, чтобы иметь дело с файлом, который не найден.
Следующий код проверяет, существует ли файл, прежде чем он
пытается его открыть. Если файл не существует, отображается сообщение, удобное
для пользователя, и код выходит из подпрограммы.
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.
Заявление об ошибке
Как мы видели, есть два способа обработки ошибок во время
выполнения
- Ожидаемые ошибки — напишите конкретный код для
их обработки. - Неожиданные ошибки — используйте операторы
обработки ошибок VBA для их обработки.
Оператор VBA On Error используется для обработки ошибок.
Этот оператор выполняет некоторые действия при возникновении ошибки во время
выполнения.
Есть четыре различных способа использовать это утверждение
- On Error Goto 0 — код останавливается на строке с ошибкой и отображает сообщение.
- On Error Resume Next — код перемещается на следующую строку. Сообщение об ошибке не отображается.
- On Error Goto [label] — код перемещается на определенную строку или метку. Сообщение об ошибке не отображается. Это тот, который мы используем для обработки ошибок.
- 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
Вторая строка присваивания приводит к ошибке деления на ноль. Когда мы запустим этот код, мы получим сообщение об ошибке, показанное на скриншоте ниже.
Когда появляется ошибка, вы можете выбрать End или Debug
Если вы выберете Конец, то приложение просто остановится.
Если вы выберете Отладить, приложение остановится на строке
ошибки, как показано на скриншоте ниже.
Это нормально, когда вы пишете код 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 переходит на метку 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:\temp\logging.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. В этом разделе я покажу вам, как
реализовать простую стратегию обработки ошибок, которую вы можете использовать
во всех своих приложениях.
Основная реализация
Это простой обзор нашей стратегии
- Поместите строку On Error Goto Label в начале нашего верхнего Sub.
- Поместите Label у обработки ошибок в конце нашего верхнего
Sub. - Если происходит ожидаемая ошибка, обработайте ее и продолжайте.
- Если приложение не может продолжить работу, используйте Err.Raise для перехода к метке обработки ошибок.
- В случае непредвиденной ошибки код автоматически перейдет к метке обработки ошибок.
На следующем рисунке показан обзор того, как это выглядит
Следующий код показывает простую реализацию этой стратегии
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 чем-либо полезным, поэтому мы
должны сделать это сами.
В этом разделе я собираюсь представить более полную
стратегию ошибок. Я написал два сабвуфера, которые выполняют всю тяжелую
работу, поэтому все, что вам нужно сделать, это добавить их в свой проект.
Целью этой стратегии является предоставление вам стека * и
номера строки в случае возникновения ошибки.
* Стек — это список вспомогательных функций, которые
использовались в данный момент при возникновении ошибки.
Это наша стратегия
- Разместите обработку ошибок во всех
подпрограммах. - Когда происходит ошибка, обработчик ошибок
добавляет подробности к ошибке и вызывает ее снова. - Когда ошибка достигает самой верхней
подпрограммы, она отображается.
Мы просто «всплываем» из-за ошибки. Следующая диаграмма
показывает простое визуальное представление о том, что происходит, когда в Sub3
возникает ошибка
Единственная грязная часть этого — правильное форматирование
строк. Я написал две подводные лодки, которые справляются с этим, поэтому он
позаботится о вас.
Это две вспомогательные подводные лодки
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
Результат выглядит так
Если в вашем проекте есть номера строк, результат будет содержать номер строки ошибки.
Примечание: вы можете получить следующую ошибку при использовании этого кода:
“Programmatic Access to Visual Basic Project is not trusted”
Чтобы решить эту проблему, выполните следующие действия.
- Перейдите в раздел «Разработчик» на ленте и
нажмите «Macro Security», которая находится под кодом. - Нажмите «Настройка макроса» в левом списке.
- Поставьте флажок в поле «Доверительный доступ к
объектной модели проекта VBA». - Нажмите Ok.
Обработка ошибок в двух словах
- Обработка ошибок используется для обработки ошибок, возникающих во время работы приложения.
- Вы пишете определенный код для обработки ожидаемых ошибок. Вы используете оператор обработки ошибок VBA
On Error Goto [label] для отправки VBA на метку при возникновении непредвиденной ошибки. - Вы можете получить подробную информацию об ошибке из Err.Description.
- Вы можете создать свою собственную ошибку, используя Err.Raise.
- Использование одного оператора On Error в самой верхней подпрограмме перехватит все ошибки в подпрограммах, которые вызываются отсюда.
- Если вы хотите записать имя Sub с ошибкой, вы можете обновить ошибку и сбросить ее.
- Вы можете использовать журнал для записи информации о приложении, когда оно запущено.
This answer does not address the Debug button (you’d have to design a form and use the buttons on that to do something like the method in your next question). But it does address this part:
now I don’t want to lose the comfortableness of the default handler which also point me to the exact line where the error has occured.
First, I’ll assume you don’t want this in production code — you want it either for debugging or for code you personally will be using. I use a compiler flag to indicate debugging; then if I’m troubleshooting a program, I can easily find the line that’s causing the problem.
# Const IsDebug = True
Sub ProcA()
On Error Goto ErrorHandler
' Main code of proc
ExitHere:
On Error Resume Next
' Close objects and stuff here
Exit Sub
ErrorHandler:
MsgBox Err.Number & ": " & Err.Description, , ThisWorkbook.Name & ": ProcA"
#If IsDebug Then
Stop ' Used for troubleshooting - Then press F8 to step thru code
Resume ' Resume will take you to the line that errored out
#Else
Resume ExitHere ' Exit procedure during normal running
#End If
End Sub
Note: the exception to Resume
is if the error occurs in a sub-procedure without an error handling routine, then Resume
will take you to the line in this proc that called the sub-procedure with the error. But you can still step into and through the sub-procedure, using F8 until it errors out again. If the sub-procedure’s too long to make even that tedious, then your sub-procedure should probably have its own error handling routine.
There are multiple ways to do this. Sometimes for smaller programs where I know I’m gonna be stepping through it anyway when troubleshooting, I just put these lines right after the MsgBox statement:
Resume ExitHere ' Normally exits during production
Resume ' Never will get here
Exit Sub
It will never get to the Resume statement, unless you’re stepping through and set it as the next line to be executed, either by dragging the next statement pointer to that line, or by pressing CtrlF9 with the cursor on that line.
Here’s an article that expands on these concepts: Five tips for handling errors in VBA. Finally, if you’re using VBA and haven’t discovered Chip Pearson’s awesome site yet, he has a page explaining Error Handling In VBA.
Error handling refers to the way runtime errors are handled. Error handling in VBA is done using the On Error statement and the Err object. Runtime errors can be generated by attempting to execute error-causing code or they can be raised explicitly using the Err.Raise method. There are a number of built-in types of runtime errors, and custom errors can be defined as well. Each type of runtime error has a unique number which can be used to determine at runtime which type of error has occurred and respond accordingly.
On Error
The On Error statement is used to control what happens when a runtime error occurs. The On Error statement sets or removes the current error handling scope. When a runtime error occurs in VBA the error trap is triggered and if an On Error statement has been set, VBA will respond according to which type of On Error statement was used.
Statement | Description |
---|---|
On Error Resume Next | Skips lines of code that cause errors. Use with caution. |
On Error GoTo Line | When an error occurs execution will jump to a specified label or line number. |
On Error GoTo 0 | Clears the current error and disables error handling. |
On Error GoTo -1 | Clears the current error and resets the error trap. |
Resume | When used after the On Error GoTo statement, Resume will continue execution from the line of code that caused the error. |
Resume Next | When used after the On Error GoTo statement, Resume Next will continue execution from the line of code directly after the line that caused the error. |
Resume Line | When used after the On Error GoTo statement, Resume Line will jump to a specified label or line number and continue execution. |
On Error Resume Next
Public Sub Example()
On Error Resume Next
Err.Raise 1004
Debug.Print "Error was skipped"
End Sub
On Error GoTo Line
Public Sub Example()
On Error GoTo HandleError
Err.Raise 1004
Exit Sub
HandleError:
Debug.Print "Error Handled"
End Sub
Note: It is not recommended to use line numbers.
Public Sub Example()
10
20 On Error GoTo 80
30
40 Err.Raise 1004
50
60 Exit Sub
70
80 Debug.Print "Error Handled"
90
End Sub
On Error GoTo…Resume
Public Sub Example()
Dim N As Long
N = 0
On Error GoTo HandleError
'Divide by zero error will be fixed by error handler
Debug.Print 1 / N
Debug.Print "Error Handled."
Exit Sub
HandleError:
If Err.Number = 11 Then
Debug.Print "Handling 'Division by zero' Error..."
N = 1
Resume
Else
Err.Raise Err.Number
End If
End Sub
On Error GoTo…Resume Next
Public Sub Example()
On Error GoTo HandleError
Err.Raise 1004
Debug.Print "Error Handled. Resuming Next..."
Exit Sub
HandleError:
Debug.Print "Handling Error..."
Resume Next
End Sub
On Error GoTo…Resume Line
Public Sub Example()
On Error GoTo HandleError
Err.Raise 1004
Continue:
Debug.Print "Resuming..."
Exit Sub
HandleError:
Debug.Print "Error Handled"
Resume Continue
End Sub
Note: It is not recommended to use line numbers.
Public Sub Example()
10
20 On Error GoTo 100
30
40 Err.Raise 1004
50
60 Debug.Print "Resuming..."
70
80 Exit Sub
90
100 Debug.Print "Error Handled"
110 Resume 60
120
End Sub
On Error GoTo 0
Public Sub Example()
On Error Resume Next
Err.Raise 1004 'Error will be skipped
On Error GoTo 0
Err.Raise 1004 'Error will be raised
End Sub
On Error GoTo -1
Public Sub Example()
On Error GoTo HandleError1
Err.Raise 1004
Exit Sub
HandleError1:
Debug.Print "HandleError1"
On Error GoTo -1
On Error GoTo HandleError2
Err.Raise 1004
Exit Sub
HandleError2:
Debug.Print "HandleError2"
Exit Sub
End Sub
The Err Object
The Err Object is used to access information about a runtime error that has occurred. When a runtime error occurs, the Err object’s properties are filled with information about the error. The Err object can also be used to raise errors explicitly.
Member | Description |
---|---|
Clear | Clears properties of the Err object. Does NOT reset error trap or clear error handling scope. |
Description | A text description of the error. |
HelpContext | The context ID for a topic in a help file. |
HelpFile | The path to help file. |
LastDllError | Returns a system error code produced by a call to a dynamic-link library (DLL). Read-only. Always returns zero on Mac. |
Number | The error number, 0 through 65535. |
Raise | Raises a specified runtime error. |
Source | The name of the object or application that originated the error. |
The Err Object is a Singleton
The Err object has a single default global instance and cannot be instantiated. The Err object can be accessed anywhere in VBA just by typing Err.
Public Sub Example()
Err.Raise 1004 'No need to instantiate Err object
End Sub
Public Sub Example()
Dim E As ErrObject
Set E = New ErrObject 'Causes error
End Sub
Properties
The Err object’s properties are filled with data when a runtime error occurs. The Number property is especially important because it can be used to dynamically respond to different types of errors. If no runtime error has occurred, the Number property will be 0. Therefore, to determine if an error has occurred in a particular line, the Number property can be checked to see if it is 0 or not.
Public Sub Example()
On Error Resume Next
Err.Raise 1004
If Err.Number <> 0 Then
With Err
Debug.Print "Number: " & .Number
Debug.Print "Description: " & .Description
Debug.Print "Source: " & .Source
Debug.Print "HelpFile: " & .HelpFile
Debug.Print "HelpContext: " & .HelpContext
Debug.Print "LastDllError: " & .LastDllError
End With
Err.Raise Err.Number
Else
Debug.Print "No Error"
End If
End Sub
Clearing The Err Object
The Err object can be reset in a few different ways. The Err object is reset when Err.Clear is called, a Resume or Resume Next statement is executed for the error, or another On Error statement is executed. Exiting an error-causing procedure does not reset the Err object.
Note: Exiting an error-causing procedure does not reset the Err object.
Public Sub Example()
Call ErrorCausingProcedure1
Debug.Print Err.Number 'Prints 1004
Call ErrorCausingProcedure2
Debug.Print Err.Number 'Prints 0
Call ErrorCausingProcedure3
Debug.Print Err.Number 'Prints 0
Call ErrorCausingProcedure4
Debug.Print Err.Number 'Prints 0
End Sub
Public Sub ErrorCausingProcedure1()
'Exiting procedure doe NOT reset the Err object
On Error Resume Next
Err.Raise 1004
End Sub
Public Sub ErrorCausingProcedure2()
'Calling Err.Clear resets the Err object
On Error Resume Next
Err.Raise 1004
Err.Clear
End Sub
Public Sub ErrorCausingProcedure3()
'Resume Next resets the Err object
On Error GoTo HandleError
Err.Raise 1004
Exit Sub
HandleError:
Resume Next
End Sub
Public Sub ErrorCausingProcedure4()
'On Error statement resets the Err object
On Error Resume Next
Err.Raise 1004
On Error GoTo 0
End Sub
Calling Err.Clear only clears the Err object. Err.Clear does not reset the error handling trap or end the error handling scope. On Error GoTo -1 will clear the Err object and reset error trapping, allowing another error to be raised. On Error GoTo 0 will clear the Err object and clear the error handling scope.
Public Sub Example()
On Error Resume Next
'Error is skipped
Err.Raise 1004
'Prints 1004
Debug.Print Err.Number
'Err object is reset
Err.Clear
'Prints 0
Debug.Print Err.Number
'Error is skipped because error handling scope was not reset
Err.Raise 1004
'Prints 1004
Debug.Print Err.Number
'Clears Err object and error handling scope
On Error GoTo 0
'Prints 0
Debug.Print Err.Number
'Raises a runtime error
Err.Raise 1004
End Sub
Error Trapping Options
Error Trapping options can be selected which can override error handling code in VBA. To change error trapping options navigate to Tools → Options → General in the Visual Basic Editor.
Option | Description |
---|---|
Break on All Errors | Will enter break mode when any error is encountered regardless of error handling code. |
Break in Class Module | Will enter break mode and show errors inside class modules. |
Break on Unhandled Errors | This is the default setting. Will enter break mode when an error is encountered and it is not handled by code. |
CVErr Function
The CVErr function can be used to return an error from a function. CVErr returns a value of type Variant with subtype Error. Only variables of type Variant can be assigned a value using the CVErr function. CVErr can take any error number as an argument. CVErr can be used to return a cell error from a user-defined function that is intended for use in spreadsheets.
Option Explicit
Public Function ReturnValueError() As Variant
'Shows #VALUE Error in cell
ReturnValueError = CVErr(xlErrValue)
End Function
xlErr Constant | Cell Error |
---|---|
xlErrBlocked | #BLOCKED! |
xlErrCalc | #CALC! |
xlErrConnect | #CONNECT! |
xlErrDiv0 | #DIV/0! |
xlErrField | #FIELD! |
xlErrGettingData | #GETTING_DATA |
xlErrNA | #N/A |
xlErrName | #NAME? |
xlErrNull | #NULL! |
xlErrNum | #NUM! |
xlErrRef | #REF! |
xlErrSpill | #SPILL! |
xlErrUnknown | #UNKNOWN! |
xlErrValue | #VALUE! |
IsError Function
The IsError function returns True if the argument expression evaluates to an error. IsError can be used to test if a cell value contains an error or a user-defined function returns an error. To return an error from a function use the CVErr function.
Option Explicit
Public Sub Example()
If IsError(Range("A1").Value) Then
Debug.Print "Range A1 contains an error."
End If
Dim E As Variant
E = ReturnError()
If IsError(E) Then
Debug.Print "E is Error: " & CStr(E)
End If
End Sub
Public Function ReturnError() As Variant
ReturnError = CVErr(xlErrValue)
End Function
Error Function
The Error/Error$ function is used to return the description text of an error. The Error function can be used to return a specific error description based on an error number or it can return the description text of the last error to occur.
Specific Error Description
Pass the optional ErrorNumber argument to the Error function to return a specific error description. Although the Error function can take a number between -2147483648 and 65535, it should be intended for use with the range 0 through 65535. If the error number is outside the valid range an Overflow runtime error will occur. If the error number is within the valid range but is not defined, the message «Application-defined or object-defined error» will be returned.
Public Sub Example()
Debug.Print Error(5) 'Prints: Invalid procedure call or argument
End Sub
Most Recent Error Description
Call the Error function with no ErrorNumber argument to return the description text for the last error to occur. If no error has occurred, a zero-length string will be returned. The Err.Description property can be used to get the text description of the most recent runtime error instead of using the Error function.
Public Sub Example()
On Error Resume Next
Err.Raise 5
Debug.Print Error() 'Prints: Invalid procedure call or argument
End Sub
Raising Errors
Use the Err.Raise method to raise a runtime error. Errors should be raised when an unacceptable state has been reached in a program. Existing VBA error numbers can be used to raise errors or custom error numbers can be created.
Raising Existing Errors
An appropriate VBA error number can be selected which describes the error.
Public Function RandomLong(MinValue As Long, MaxValue As Long) As Long
If MinValue > MaxValue Then
Err.Raise 5
End If
Randomize
RandomLong = Int((MaxValue - MinValue + 1) * Rnd + MinValue)
End Function
User-Defined Errors
To raise a user-defined error, create an error number by using the vbObjectError constant and adding a number between 513 and 65535. The range 0 through 512 is reserved for system errors. The vbObjectError constant has the value -2147221504 so user-defined errors will be negative. To derive the positive portion of a user-defined error simply subtract the vbObjectError constant from the error number.
Public Sub Example()
On Error GoTo HandleError
Err.Raise Number:=vbObjectError + 513, Description:="Custom Error"
Exit Sub
HandleError:
Debug.Print Err.Number - vbObjectError, Err.Description 'Prints: 513 Custom Error
Resume Next
End Sub
Error Statement
The Error statement raises a runtime error for a given error number. The Error statement is included for backward compatibility with older versions of VBA and Err.Raise should be used instead for new code.
Public Sub Example()
'Backward compatible
Error 5
'Use this for new code
Err.Raise 5
End Sub
Error Numbers
Runtime errors each have a number used to identify what type of error it is. Error numbers can be used with the Err.Raise method, the Error statement, and the Error function. When a runtime error occurs, the Err.Number property will be set to the number associated with the type of error. Any positive error number not listed in the table below returns «Application-defined or object-defined error».
Error Number | Error Text |
---|---|
3 | Return without GoSub |
5 | Invalid procedure call or argument |
6 | Overflow |
7 | Out of memory |
9 | Subscript out of range |
10 | This array is fixed or temporarily locked |
11 | Division by zero |
13 | Type mismatch |
14 | Out of string space |
16 | Expression too complex |
17 | Can’t perform requested operation |
18 | User interrupt occurred |
20 | Resume without error |
28 | Out of stack space |
35 | Sub or Function not defined |
47 | Too many DLL application clients |
48 | Error in loading DLL |
49 | Bad DLL calling convention |
51 | Internal error |
52 | Bad file name or number |
53 | File not found |
54 | Bad file mode |
55 | File already open |
57 | Device I/O error |
58 | File already exists |
59 | Bad record length |
61 | Disk full |
62 | Input past end of file |
63 | Bad record number |
67 | Too many files |
68 | Device unavailable |
70 | Permission denied |
71 | Disk not ready |
74 | Can’t rename with different drive |
75 | Path/File access error |
76 | Path not found |
91 | Object variable or With block variable not set |
92 | For loop not initialized |
93 | Invalid pattern string |
94 | Invalid use of Null |
96 | Unable to sink events of object because the object is already firing events to the maximum number of event receivers that it supports |
97 | Can not call friend function on object which is not an instance of defining class |
98 | A property or method call cannot include a reference to a private object, either as an argument or as a return value |
321 (1 — 2) | Invalid file format |
322 | Can’t create necessary temporary file |
325 | Invalid format in resource file |
380 (1 — 2) | Invalid property value |
381 | Invalid property array index |
382 | Set not supported at runtime |
383 | Set not supported (read-only property) |
385 | Need property array index |
387 | Set not permitted |
393 | Get not supported at runtime |
394 | Get not supported (write-only property) |
422 | Property not found |
423 | Property or method not found |
424 | Object required |
429 | ActiveX component can’t create object |
430 | Class does not support Automation or does not support expected interface |
432 | File name or class name not found during Automation operation |
438 | Object doesn’t support this property or method |
440 | Automation error |
442 | Connection to type library or object library for remote process has been lost. Press OK for dialog to remove reference. |
443 | Automation object does not have a default value |
445 | Object doesn’t support this action |
446 | Object doesn’t support named arguments |
447 | Object doesn’t support current locale setting |
448 | Named argument not found |
449 | Argument not optional |
450 | Wrong number of arguments or invalid property assignment |
451 | Property let procedure not defined and property get procedure did not return an object |
452 | Invalid ordinal |
453 | Specified DLL function not found |
454 | Code resource not found |
455 | Code resource lock error |
457 | This key is already associated with an element of this collection |
458 | Variable uses an Automation type not supported in Visual Basic |
459 | Object or class does not support the set of events |
460 (1 — 2) | Invalid clipboard format |
461 | Method or data member not found |
462 | The remote server machine does not exist or is unavailable |
463 | Class not registered on local machine |
481 (1 — 2) | Invalid picture |
482 (1 — 2) | Printer error |
735 | Can’t save file to TEMP |
744 | Search text not found |
746 | Replacements too long |
1004 | Application-defined or object-defined error |
31001 | Application-defined or object-defined error. *Out of memory |
31004 | Application-defined or object-defined error. *No object |
31018 | Application-defined or object-defined error. *Class is not set |
31027 | Application-defined or object-defined error. *Unable to activate object |
31032 | Application-defined or object-defined error. *Unable to create embedded object |
31036 | Application-defined or object-defined error. *Error saving to file |
31037 | Application-defined or object-defined error. *Error loading from file |
Обработка ошибок в 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.
In this Article
- VBA Errors Cheat Sheet
- Errors
- VBA Error Handling
- VBA On Error Statement
- On Error GoTo 0
- On Error Resume Next
- Err.Number, Err.Clear, and Catching Errors
- On Error GoTo Line
- VBA IsError
- If Error VBA
- VBA Error Types
- Runtime Errors
- Syntax Errors
- Compile Errors
- Debug > Compile
- OverFlow Error
- Other VBA Error Terms
- VBA Catch Error
- VBA Ignore Error
- VBA Throw Error / Err.Raise
- VBA Error Trapping
- VBA Error Message
- VBA Error Handling in a Loop
- VBA Error Handling in Access
VBA Errors Cheat Sheet
Errors
On Error – Stop code and display error
On Error Goto 0
On Error – Skip error and continue running
On Error Resume Next
On Error – Go to a line of code [Label]
On Error Goto [Label]
Clears (Resets) Error
On Error GoTo –1
Show Error number
MsgBox Err.Number
Show Description of error
MsgBox Err.Description
Function to generate own error
Err.Raise
See more VBA “Cheat Sheets” and free PDF Downloads
VBA Error Handling
VBA Error Handling refers to the process of anticipating, detecting, and resolving VBA Runtime Errors. The VBA Error Handling process occurs when writing code, before any errors actually occur.
VBA Runtime Errors are errors that occur during code execution. Examples of runtime errors include:
- Referencing a non-existent workbook, worksheet, or other object (Run-time Error 1004)
- Invalid data ex. referencing an Excel cell containing an error (Type Mismatch – Run-time Error 13)
- Attempting to divide by zero
VBA On Error Statement
Most VBA error handling is done with the On Error Statement. The On Error statement tells VBA what to do if it encounters an error. There are three On Error Statements:
- On Error GoTo 0
- On Error Resume Next
- On Error GoTo Line
On Error GoTo 0
On Error GoTo 0 is VBA’s default setting. You can restore this default setting by adding the following line of code:
On Error GoTo 0
When an error occurs with On Error GoTo 0, VBA will stop executing code and display its standard error message box.
Often you will add an On Error GoTo 0 after adding On Error Resume Next error handling (next section):
Sub ErrorGoTo0()
On Error Resume Next
ActiveSheet.Shapes("Start_Button").Delete
On Error GoTo 0
'Run More Code
End Sub
On Error Resume Next
On Error Resume Next tells VBA to skip any lines of code containing errors and proceed to the next line.
On Error Resume Next
Note: On Error Resume Next does not fix an error, or otherwise resolve it. It simply tells VBA to proceed as if the line of code containing the error did not exist. Improper use of On Error Resume Next can result in unintended consequences.
A great time to use On Error Resume Next is when working with objects that may or may not exist. For example, you want to write some code that will delete a shape, but if you run the code when the shape is already deleted, VBA will throw an error. Instead you can use On Error Resume Next to tell VBA to delete the shape if it exists.
On Error Resume Next
ActiveSheet.Shapes("Start_Button").Delete
On Error GoTo 0
Notice we added On Error GoTo 0 after the line of code containing the potential error. This resets the error handling.
In the next section we’ll show you how to test if an error occurred using Err.Number, giving you more advanced error handling options.
VBA Coding Made Easy
Stop searching for VBA code online. Learn more about AutoMacro — A VBA Code Builder that allows beginners to code procedures from scratch with minimal coding knowledge and with many time-saving features for all users!
Learn More
Err.Number, Err.Clear, and Catching Errors
Instead of simply skipping over a line containing an error, we can catch the error by using On Error Resume Next and Err.Number.
Err.Number returns an error number corresponding with the type of error detected. If there is no error, Err.Number = 0.
For example, this procedure will return “11” because the error that occurs is Run-time error ’11’.
Sub ErrorNumber_ex()
On Error Resume Next
ActiveCell.Value = 2 / 0
MsgBox Err.Number
End Sub
Error Handling with Err.Number
The true power of Err.Number lies in the ability to detect if an error occurred (Err.Number <> 0). In the example below, we’ve created a function that will test if a sheet exists by using Err.Number.
Sub TestWS()
MsgBox DoesWSExist("test")
End Sub
Function DoesWSExist(wsName As String) As Boolean
Dim ws As Worksheet
On Error Resume Next
Set ws = Sheets(wsName)
'If Error WS Does not exist
If Err.Number <> 0 Then
DoesWSExist = False
Else
DoesWSExist = True
End If
On Error GoTo -1
End Function
Note: We’ve added a On Error GoTo -1 to the end which resets Err.Number to 0 (see two sections down).
With On Error Resume Next and Err.Number, you can replicate the “Try” & “Catch” functionality of other programming languages.
On Error GoTo Line
On Error GoTo Line tells VBA to “go to” a labeled line of code when an error is encountered. You declare the Go To statement like this (where errHandler is the line label to go to):
On Error GoTo errHandler
and create a line label like this:
errHandler:
Note: This is the same label that you’d use with a regular VBA GoTo Statement.
Below we will demonstrate using On Error GoTo Line to Exit a procedure.
On Error Exit Sub
You can use On Error GoTo Line to exit a sub when an error occurs.
You can do this by placing the error handler line label at the end of your procedure:
Sub ErrGoToEnd()
On Error GoTo endProc
'Some Code
endProc:
End Sub
or by using the Exit Sub command:
Sub ErrGoToEnd()
On Error GoTo endProc
'Some Code
GoTo skipExit
endProc:
Exit Sub
skipExit:
'Some More Code
End Sub
Err.Clear, On Error GoTo -1, and Resetting Err.Number
After an error is handled, you should generally clear the error to prevent future issues with error handling.
After an error occurs, both Err.Clear and On Error GoTo -1 can be used to reset Err.Number to 0. But there is one very important difference: Err.Clear does not reset the actual error itself, it only resets the Err.Number.
What does that mean? Using Err.Clear, you will not be able to change the error handling setting. To see the difference, test out this code and replace On Error GoTo -1 with Err.Clear:
Sub ErrExamples()
On Error GoTo errHandler:
'"Application-defined" error
Error (13)
Exit Sub
errHandler:
' Clear Error
On Error GoTo -1
On Error GoTo errHandler2:
'"Type mismatch" error
Error (1034)
Exit Sub
errHandler2:
Debug.Print Err.Description
End Sub
Typically, I recommend always using On Error GoTo -1, unless you have a good reason to use Err.Clear instead.
VBA On Error MsgBox
You might also want to display a Message Box on error. This example will display different message boxes depending on where the error occurs:
Sub ErrorMessageEx()
Dim errMsg As String
On Error GoTo errHandler
'Stage 1
errMsg = "An error occured during the Copy & Paste stage."
'Err.Raise (11)
'Stage 2
errMsg = "An error occured during the Data Validation stage."
'Err.Raise (11)
'Stage 3
errMsg = "An error occured during the P&L-Building and Copy-Over stage."
Err.Raise (11)
'Stage 4
errMsg = "An error occured while attempting to log the Import on the Setup Page"
'Err.Raise (11)
GoTo endProc
errHandler:
MsgBox errMsg
endProc:
End Sub
Here you would replace Err.Raise(11) with your actual code.
VBA IsError
Another way to handle errors is to test for them with the VBA ISERROR Function. The ISERROR Function tests an expression for errors, returning TRUE or FALSE if an error occurs.
Sub IsErrorEx()
MsgBox IsError(Range("a7").Value)
End Sub
VBA Programming | Code Generator does work for you!
If Error VBA
You can also handle errors in VBA with the Excel IFERROR Function. The IFERROR Function must be accessed by using the WorksheetFunction Class:
Sub IfErrorEx()
Dim n As Long
n = WorksheetFunction.IfError(Range("a10").Value, 0)
MsgBox n
End Sub
This will output the value of Range A10, if the value is an error, it will output 0 instead.
VBA Error Types
Runtime Errors
As stated above:
VBA Runtime Errors are errors that occur during code execution. Examples of runtime errors include:
- Referencing a non-existent workbook, worksheet, or other object
- Invalid data ex. referencing an Excel cell containing an error
- Attempting to divide by zero
You can “error handle” runtime errors using the methods discussed above.
Syntax Errors
VBA Syntax Errors are errors with code writing. Examples of syntax errors include:
- Mispelling
- Missing or incorrect punctuation
The VBA Editor identifies many syntax errors with red highlighting:
The VBA Editor also has an option to “Auto Syntax Check”:
When this is checked, the VBA Editor will generate a message box alerting you syntax errors after you enter a line of code:
I personally find this extremely annoying and disable the feature.
Compile Errors
Before attempting to run a procedure, VBA will “compile” the procedure. Compiling transforms the program from source code (that you can see) into executable form (you can’t see).
VBA Compile Errors are errors that prevent the code from compiling.
A good example of a compile error is a missing variable declaration:
Other examples include:
- For without Next
- Select without End Select
- If without End If
- Calling a procedure that does not exist
Syntax Errors (previous section) are a subset of Compile Errors.
AutoMacro | Ultimate VBA Add-in | Click for Free Trial!
Debug > Compile
Compile errors will appear when you attempt to run a Procedure. But ideally, you would identify compile errors prior to attempting to run the procedure.
You can do this by compiling the project ahead of time. To do so, go to Debug > Compile VBA Project.
The compiler will “go to” the first error. Once you fix that error, compile the project again. Repeat until all errors are fixed.
You can tell that all errors are fixed because Compile VBA Project will be grayed out:
OverFlow Error
The VBA OverFlow Error occurs when you attempt to put a value into a variable that is too large. For example, Integer Variables can only contain values between -32,768 to 32,768. If you enter a larger value, you’ll receive an Overflow error:
Instead, you should use the Long Variable to store the larger number.
Other VBA Error Terms
VBA Catch Error
Unlike other programming languages, In VBA there is no Catch Statement. However, you can replicate a Catch Statement by using On Error Resume Next and If Err.Number <> 0 Then. This is covered above in Error Handling with Err.Number.
AutoMacro | Ultimate VBA Add-in | Click for Free Trial!
VBA Ignore Error
To ignore errors in VBA, simply use the On Error Resume Next statement:
On Error Resume Next
However, as mentioned above, you should be careful using this statement as it doesn’t fix an error, it just simply ignores the line of code containing the error.
VBA Throw Error / Err.Raise
To through an error in VBA, you use the Err.Raise method.
This line of code will raise Run-time error ’13’: Type mismatch:
Err.Raise (13)
VBA Error Trapping
VBA Error Trapping is just another term for VBA Error Handling.
VBA Error Message
A VBA Error Message looks like this:
When you click ‘Debug’, you’ll see the line of code that is throwing the error:
AutoMacro | Ultimate VBA Add-in | Click for Free Trial!
VBA Error Handling in a Loop
The best way to error handle within a Loop is by using On Error Resume Next along with Err.Number to detect if an error has occurred (Remember to use Err.Clear to clear the error after each occurrence).
The example below will divide two numbers (Column A by Column B) and output the result into Column C. If there’s an error, the result will be 0.
Sub test()
Dim cell As Range
On Error Resume Next
For Each cell In Range("a1:a10")
'Set Cell Value
cell.Offset(0, 2).Value = cell.Value / cell.Offset(0, 1).Value
'If Cell.Value is Error then Default to 0
If Err.Number <> 0 Then
cell.Offset(0, 2).Value = 0
Err.Clear
End If
Next
End Sub
VBA Error Handling in Access
All of the above examples work exactly the same in Access VBA as in Excel VBA.
Function DelRecord(frm As Form)
'this function is used to delete a record in a table from a form
On Error GoTo ending
With frm
If .NewRecord Then
.Undo
Exit Function
End If
End With
With frm.RecordsetClone
.Bookmark = frm.Bookmark
.Delete
frm.Requery
End With
Exit Function
ending:
End
End Function