Чтобы VBA не имел дела с ошибками выполнения, а взять заботу о них на себя, процедуры нужно снабдить обработчиком ошибок - блоком программного кода, выполняемым только тогда, когда происходит ошибка. Если при выполнении процедуры что-то пойдет не так, VBA вызовет этот обработчик ошибок, чтобы в нем выяснить, какого типа ошибка произошла, и в зависимости от сложившейся ситуации предпринять предусмотренные вами действия.
Чтобы добавить в процедуру программный код обработчика ошибок, нужно сделать следующее:
* добавить в начало процедуры оператор On Error, сообщающий VBA, где найти программный код обработчика ошибок;
* в конец процедуры добавить оператор Exit Sub (или Exit Function), за котор рым должен следовать программный код обработчика ошибок;
* создать программный код самого обработчика ошибок, начало которого должно идентифицироваться некоторой меткой.
Все три шага при этом обязательны. Например, без оператора On Error VBA не узнает, что обработчик ошибок вами вообще предусмотрен.
Оператор On Error делает обработчик ошибок доступным, сообщая VBA о том, где найти этот обработчик ошибок в программном коде. В использовании этот оператор выглядит так: On Error GoTo метка, где метка - это метка, идентифицирующая в процедуре начало программного кода обработчика ошибок.
Вот пример использования оператора On Error:
Sub ErrorHandlerDemo()
On Error GoTo ErrorHandler
MamaVariable = DoThisFunction (X,Y,Z)
PapaVariable = DoThatProcedure
EabyVariable = MamaVariable + PapaVariable
' здесь завершается выполнение процедуры, когда ошибок нет
Exit Sub
Error Handler:
(здесь размещаются операторы обработчика ошибок)
End Sub
Вам полезно знать, что существуют еще две формы оператора On Error.
* On Error GoTo 0 отменяет программную обработку ошибок в процедуре, начиная с данного места, и выполняет очистку объекта Err. Используйте этот оператор чтобы отменить действие ранее выполненного оператора On Error GoTo метка, если по каким-то причинам вы предпочтете отказаться от услуг своего обработчика ошибок в пользу "крикливо бесцеремонного" обработчика VBA.
* On Error Resume Next дает указание VBA игнорировать строку программного кода, ставшую причиной ошибки, и продолжить выполнение со следующей за ней строки. Ясно, что игнорирование ошибки не устраняет ее, но оператор On Error Resume Next оказывается полезным при работе с объектами из содержащего программу приложения или других компонентов, которые создали не вы, - эти достаточно тонкие вопросы обсуждаются в главе 14.
Если обработчик ошибок является частью той процедуры, в которой он размещен, VBA будет выполнять операторы обработчика ошибок при каждом выполнении процедуры. Ясно, что этого быть не должно. Нужно, чтобы обработчик ошибок выполнялся только тогда, когда в программе возникает ошибка.
Чтобы обработчик ошибок не выполнялся, когда это не нужно, необходимо добавить перед началом программного кода обработчика ошибок оператор Exit, как показано выше в примере из подраздела "Использование оператора On Error". Если это процедура типа Sub, то используйте оператор Exit Sub, а для процедуры типа Function используйте Exit Function.
Сам по себе обработчик ошибок состоит из следующих компонентов:
* метка, показывающая, где начинается программный код обработчика ошибок;
* программный код, призванный определить тип возникшей ошибки;
* программный код, обрабатывающий ошибку;
* оператор, дающий указание продолжить выполнение основной части процедуры (необязательный компонент).
Для идентификации начала программного кода обработчика ошибок поместите в первой строке обработчика ошибок стандартную метку VBA (напомню, что метка представляет собой любое допустимое слово, за которым следует двоеточие). Как уже объяснялось выше, в случае возникновения ошибки этой метке должен передать управление оператор On Error. В следующем примере такой меткой является ThisIsTheErrorHandler:
* * *
ThisIsTheErrorHandler:
* * *
( здесь размещаются операторы обработчика ошибок)
* * *
End Sub
Программный код обработчика ошибок почти всегда размешают в самом конце процедуры, поэтому и в данном примере обработчик ошибок завершается оператором End Sub.
Перед обработчиком ошибок ставятся две главные задачи- выяснение типа возникшей ошибки и выполнение некоторых действий по ее исправлению. По сути, эти задачи различны, но на практике они выполняются почти одновременно.
Как правило, при выяснении того, что произошло, используется объект Err VBA. Объект Err всегда доступен в любой VBA-программе. Его можно использовать сразу, без предварительного создания его экземпляра. В объекте Err VBA автоматически сохраняет информацию о последней из случившихся в программе ошибок. Вашей программе остается только выяснить значения свойств объекта Err, в частности значения свойств Number (Номер) и Description (Описание).
Свойство Number сообщает номер ошибки. Вы можете присвоить значение этого свойства переменной или использовать его непосредственно в условном выражении, как в следующем примере:
Sub ЕщеОдноСообщение()
On Error GoTo ПытаюсьДуматьНоНеВыходит
* * *
(склонные к ошибкам операторы )
Exit Sub
ПытаюсьДуматьНоНеВыходит:
Select Case Err.Number
Case 7 ' выход за пределы памяти
( обработка ошибки номер 7)
Case 11 ' деление на нуль
(обработка ошибки номер 11) .
... (и т.д.)
Case Else
( обработка всех остальных ошибок)
End Select
End Sub
В этом примере оператор Select Case сравнивает значение свойства Number с рядом фиксированных значений, для каждого из которых нужно создать обрабатывающий соответствующую ошибку фрагмент программного кода. Обработка ошибки может включать следующее.
* Информирование пользователя о том, что произошло, и получение от пользователя инструкций по этому поводу с помощью окна ввода или другой специальной формы.
* Попытка получить данные снова из того же или альтернативного источника.
* Изменение неподходящих данных на подходящие с одновременной записью в файл или выводом на экран сообщения о том, что для продолжения работы пришлось эти данные изменить.
Для эффективной работы со свойством Number нужно знать, каким именно ошибкам соответствуют возвращаемые этим свойством номера. Из-за недостатка места я не могу представить здесь соответствующий список. В некоторых VBA-приложениях - к ним относятся и приложения Office 97 - информация об ошибках, встречающихся чаше всего, имеется в разделе Trappable Errors (Распознаваемые ошибки) справки по VBA. Этот раздел можно найти, напечатав trappableerrors в поле ввода на вкладке Предметный указатель в окне справки. В справочной системе Office 2000 подобного раздела мне найти не удалось.
Даже если ваш программный код не может обработать какую-то ошибку или если вы просто не хотите утруждать себя, вы все равно можете не допустить появления стандартного сообщения VBA об ошибке, использовав свойство Description (Описание) объекта Err.
Следующий фрагмент программного кода отображает исключительно вежливое сообщение об ошибке, частью которого является строка, предоставленная свойством Description:
strМоеСообщение = "С сожалением сообщаю Вам, что " _
& "в эту в целом замечательную программу все же " _
& "вкралась ошибка. Как сообщает наш надежный " _
& "источник (VBA), причиной беспокойства является "
MsgBox strМоеСообщение & Err.Description
Некоторые VBA-приложения предлагают свои объекты и функции, с помощью которых можно получить дополнительную информацию о специфических проблемах данного приложения. Например, Microsoft Access предлагает для этого специальный объект Error.
После того как обработчик ошибок завершит свою работу, вам придется решить, вернуться ли в процедуру, в которой произошла ошибка, чтобы продолжить выполнение этой процедуры, или передать управление той процедуре, из которой была вызвана процедура с ошибкой.
Если вы предпочтете продолжить выполнение текущей процедуры, поместите в обработчик ошибок оператор Resume. Оператор Resume имеет несколько вариантов.
* Если просто напечатать Resume в отдельной строке, то этот оператор вернет управление в процедуре тому же оператору, который вызвал ошибку. Это разумно, если обработчик ошибок решает проблему и вы уверены, что ошибка не возникнет вновь.
* Чтобы пропустить оператор, ставший причиной появления ошибки, используйте в обработчике ошибок оператор Resume Next. Тогда выполнение продолжится с оператора, следующего непосредственно за оператором, вызвавшим ошибку.
* Чтобы продолжить выполнение с определенного места в процедуре, используйте в обработчике ошибок оператор Resume метка. Здесь метка означает ссылку на метку, размещенную где-то в процедуре, но, очевидно, не на метку, идентифицирующую начало программного кода обработчика ошибок. Ясно, что в данном случае вы должны задать соответствующую метку в процедуре.