[an error occurred while processing this directive]

В начало

Введение

1-й час. Знакомство с Visual Basic for Applications

2-й час. Работа с макросами

3-й час. Работа с элементами управления

4-й час. Переменные и константы

5-й час. Ввод данных

6-й час. Логика условных операторов

7-й час. Циклические вычисления

8-й час. Введение в объекты

9-й час. Основные объекты Excel

10-й час. Объект Range

11-й час. Редактор Visual Basic

12-й час. Отладка программ

13-й час. Обработка ошибок

14-й час. Экранные формы

15-й час. Автоматизация экранных форм

16-й час. Панели инструментов

17-й час. Работа с меню

18-й час. Диаграммы

19-й час. Сводные таблицы

20-й час. Получение внешних данных

21-й час. Доступ к данным с помощью ADO

22-й час. Еще об ADO

23-й час. Автоматизация

24-й час. Выполнение процедур

Приложение. Ответы

13-й час. Обработка ошибок

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

В этом часе будут рассмотрены следующие вопросы.

  • Что такое "обработка ошибок".
  • Установка ловушек для ошибок.
  • Написание процедур обработки ошибок.
  • Выходы из обработчика ошибок.
  • Создание централизованного обработчика ошибок.

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

Разрешение непредвиденных ситуаций при выполнении приложений называется обработкой ошибок. Процедуры, выполняющие обработку ошибок, называются, как нетрудно догадаться, обработчиками ошибок (error handler). Их назначение - отлов (перехват) в приложении ошибок и борьба с ними. В создании обработчика ошибок можно выделить три этапа.

  1. Установка ловушек для ошибок (error trap).

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

  1. Написание процедуры обработки ошибок.

Создание кода, который определяет тип ошибки и выполняет те или иные действия для разрешения проблем, вызванных ошибкой.

  1. Создание выхода из процедуры обработки ошибок.

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

Перехват ошибок

Установка ловушек для ошибок в VBA осуществляется с помощью оператора On Error. В процедуре может быть только одна ловушка для ошибок. Но это не означает, что в процедуре возможен только один оператор On Error. Если в процедуре несколько операторов On Error, то на самом деле все равно должен выполняться только один из них.

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

  • On Error Resume

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

  • On Error Resume Next

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

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

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

Во втором способе используется оператор On Error GoTo строка, где строка - это метка (line label) в строке кода процедуры, начиная с которой располагается код обработчика ошибок. Метка представляет собой имя, заканчивающееся двоеточием, что отличает ее от других идентификаторов языка VBA. Листинг 13.1 показывает структуру процедуры, содержащую обработчик ошибок.

Листинг 13.1. Структура процедуры, содержащая обработчик ошибок

1: Sub ПроцедураСОбработчиком()

2:  On Error GoTo ErrorHandler

3:  'Далее идет тело процедуры

4:  .

5:  .

6:  .'Следующий оператор, Exit Sub или Exit Function

7:  .'(в зависимости от типа процедуры), стоит перед

8:  'меткой, с которой начинается код обработчика

9:  'ошибок. Это сделано для того, чтобы при отсутствии

10:  'ошибок обработчик не выполнялся.

11:  Exit Sub

12: 'В следующей строке расположена метка обработчика ошибок

13: ErrorHandler:

14:  'Далее идет код процедуры обработки ошибок

15:  .

16:  .

17: End Sub

Написание процедуры обработки ошибся

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

Выход из обработчика ошибок

В процедуре обработки ошибок для идентификации ошибок используются оператор If и Select и, следовательно, соответствующие условные выражения. В этих условных выражениях обычно проверяется значение свойства Number (Номер) объекта Err (Ошибка). Объект Err содержит информацию об ошибке, возникшей во время выполнения приложения, а свойство Number возвращает числовое значение, указывающее на тип ошибки. После определения типа ошибки и, возможно, выполнения каких-либо действий процедура обработки ошибок должна заканчиваться одним из следующих операторов.

  • Resume - возвращает управление оператору, при выполнении которого во: никла ошибка.
  • Resume Next - возвращает управление оператору, следующему за оператором, при выполнении которого возникла ошибка.
  • Resume метка - осуществляет переход к указанной метке.
  • End - завершает выполнение процедуры или приложения.

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

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

  1. Создайте новую процедуру под именем ПримерОбработчик.
  2. Введите код процедуры.

Dim sngValue As Single, sngDivideBy As Single

Dim sngAnswer As Single

Dim iResponse As Integer

On Error GoTo ErrorZone

sngValue = InputBox("Введите делимое")

sngDivideBy = InputBox("Введите делитель")

sngAnswer = sngValue / sngDivideBy

MsgBox "Результат деления = " & sngAnswer

Exit Sub

ErrorZone:

 Select Case Err

  Case 7

   MsgBox "He хватает памяти" & _

    Chr(13) & "Закройте неиспользуемые приложения"

   Resume

  Case 35 To 51

   MsgBox "Обратитесь к справочной системе"

  Case 11

   MsgBox "Деление на ноль"

  Case Else

   MsgBox "Неопознанная ошибка. Приложение завершается"

   End

End Select

  1. Начните выполнение процедуры. Введите число 10 в первое окно ввода.
  2. Введите 0 во второе окно ввода. После нажатия клавиши <Enter> отобразится окно с сообщением о делении на ноль.
  3. Щелкните на кнопке ОК для закрытия окна сообщения.

С помощью функции Error можно выводить текст, соответствующий возникшей ошибке. Измените процедуру ПримерОбработчик, как показано ниже (новый оператор выделен полужирным шрифтом).

Private Sub ПримерОбработчик()

 Dim sngValue As Single, sngDivideBy As Single

 Dim sngAnswer As Single

 Dim iResponse As Integer

 On Error GoTo ErrorZone

 sngValue = InputBox("Введите делимое")

 sngDivideBy = InputBox("Введите делитель")

 sngAnswer = sngValue / sngDivideBy

 MsgBox "Результат деления = " & sngAnswer

Exit Sub

ErrorZone:

 Select Case Err

  Case 7

   MsgBox "He хватает памяти" & Chr(13) & _

    "Закройте неиспользуемые приложения"

   Resume

  Case 35 To 51

   MsgBox "Обратитесь к справочной системе"

  Case 11

   MsgBox "Ошибка выполнения: " & Error

  Case Else

   MsgBox "Неопознанная ошибка. Приложение завершается"

   End

 End Select

End Sub

Начните выполнение процедуры. Введите число 5 в первое окно ввода и число 0 - во второе. Появится окно сообщения, показанное на рис. 13.1.

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

Рис. 13.1. Текст сообщения, предложенный функцией Error

Централизованный обработчик ошибок

Вместо того чтобы включать обработчик ошибок в каждую процедуру, можно создать централизованный обработчик ошибок - отдельную функцию, которая будет перехватывать ошибки, а затем, основываясь на номере ошибки, выполнять те или иные действия. Но все равно каждая процедура, в которой предусмотрена обработка ошибок, будет иметь оператор On Error. При возникновении ошибки этот оператор обращается к процедуре обработки ошибок, для которой функция-централизованный обработчик ошибок возвращает число, определяемое типом ошибки. Затем с помощью оператора Select Case выбирается оператор, осуществляющий выход из обработчика ошибок. Возможны следующие операторы выхода. (Оператор Resume описан выше.)

  • Оператор Resume.
  • Оператор Resume Next.
  • Оператор Resume метка.
  • Оператор Exit - выход из процедуры.
  • Оператор End - завершение приложения.

Обычно в локальную процедуру обработки ошибки функция-централизованный обработчик возвращает целое значение из интервала от 1 до 5 (как показано ниже), но это не правило, и вы можете создать свой централизованный обработчик, который будет более дифференцированно различать типы ошибок.

Опишем процесс создания централизованного обработчика ошибок.

  1. Добавьте новый модуль в рабочую книгу и создайте функцию с именем HandleErrors.
  2. Функция HandleErrors имеет следующий код:

Function HandleErrors(iErrNum) As Integer

 Select Case iAction

 Case 5

  'Неправильный вызов процедуры

  MsgBox Error(iErrNum) & "Обратитесь к справке"

  iAction =2

 Case 7

  'He хватает оперативной памяти

  MsgBox "Закройте все неиспользуемые приложения"

  iAction = 1

 Case 11

  'Деление на ноль

  MsgBox "Деление на ноль. Введите другое значение"

  iAction = 1

 Case 48,49,51

  'Ошибка загрузки библиотек DLL

  MsgBox iErrNum & "Обратитесь к справке"

  iAction = 5

 Case 57

  'Ошибка ввода-вывода

  MsgBox "Вставьте дискету в дисковод А:"

  iAction = 1

 Case Else

  MsgBox "Неопознанная ошибка"

  iAction = 5

 End Select

 ErrorHandle = iAction

End Function

  1. Перейдите в процедуру ПримерОбработчик (она находится в другом модуле).
  2. Приведите код этой процедуры к следующему виду (изменения в коде выделены полужирным шрифтом):

Public Sub ПримерОбработчик()

 Dim sngValue As Single, sngDivideBy As Single

 Dim sngAnswer As Single

 Dim iResponse As Integer

 On Error GoTo ErrorZone

 sngValue = InputBox("Введите делимое")

 sngDivideBy = InputBox("Введите делитель")

 sngAnswer = sngValue / sngDivideBy

 MsgBox "Результат деления = " & sngAnswer

 Exit Sub

 ErrorZone:

  'Оператор Select использует значения,

  'возвращаемые функцией HandleErrors

  Select Case HandleErrors(Err)

  Case 1

   Resume

  Case 2

   Resume Next

  'В этой процедуре не рассматривается

  'Case 3, передающий управление в тело процедуры

  Case 4

   Exit Sub

  Case 5

   End

  End Select

End Sub

  1. Выполните процедуру.
  2. Введите 8 в первое окно ввода.
  3. Введите 0 во второе окно ввода. Это приведет к ошибке.
  4. Щелкните на кнопке ОК для закрытия окна сообщения.

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

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

Резюме

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

Вопрос и ответы

Вопрос. Можно ли искусственно вызвать ошибку?

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

Вопрос. У меня одна процедура вызывает другую, при этом вызываемая процедура не имеет обработчика ошибок, а вызывающая - имеет. Что случится, если возникнет ошибка?

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

Практикум

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

Тесты

  1. Опишите три основные этапа создания обработчика ошибок.
  2. Назовите объект и его свойство, которые применяются для определения номера ошибки.
  3. Какой оператор возвращает управление тому оператору, при выполнении которого произошла ошибка?
  4. Какой символ завершает имя метки?
  5. Какой оператор пропускает тот оператор, где произошла ошибка?
  6. Истинно или ложно следующее утверждение: каждая процедура должна иметь собственный обработчик ошибок?
  7. Какая логическая конструкция лучше всего подходит для создания обработчика ошибок?

Упражнение

Создайте следующую процедуру:

Sub ПроцСОшибкой()

 Workbooks.Open "С:\неттакогофайла.wkb"

End Sub

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

[an error occurred while processing this directive]