Access. Программирование на VBA. Профессиональная обработка ошибок

Access. Программирование на VBA. Профессиональная обработка ошибок.

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

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

При возникновении ошибки пользователи должны обязательно получать предупреждение, что позволит им разобраться в происходящем и предпринять необходимые действия. Непонятные сообщения об ошибках настолько же плохи, как и отсутствие каких бы то ни было сообщений (рис. 1). Многие ли пользователи понимают или находят полезными сообщения об ошибках типа Illegal Operation, Overflow или General Protection Fault?

РИСУНОК 1. Пример непонятного сообщения об ошибке.

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

Без обработчиков ошибок программисты вынуждены полагаться на объяснения пользователей о том, что они делали в момент возникновения ошибки. Типичный ответ пользователя: "Я не знаю". Это приводит к ненужным и занимающим время попыткам найти и обнаружить ошибку. В данной главе описан процесс создания мощного обработчика ошибок, который поможет как пользователям приложения, так и разработчику.

Существует три типа программных ошибок: синтаксические ошибки, логические ошибки и ошибки рабочего цикла.

Исключение синтаксических ошибок

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

Dim strName as

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

Dim strName as String

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

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

BankBalance = 4,576.98 RS!BankBalance = BankBalence

VBA не признает BankBalence как зарезервированное слово, поэтому полагает, что разработчик хочет создать новую переменную типа Variant со значением, принятым по умолчанию. Empty. В результате база данных обновляется значением Empty вместо необходимого значения $4,576.98.

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

Dim bytNumber as Byte (1 байт)

Необъявленная переменная (для числовых данных)

(16 байтов)

Необъявленная переменная (символьные или строковые данные)

(22 байта)

В данном примере необъявленная переменная получает тип Variant. Чтобы сделать объявление переменных обязательным, необходимо в редакторе Visual Basic открыть модуль кода. Затем в меню следует выбрать команду Tools | Options (Сервис | Параметры). В диалоговом окне Options (Параметры) во вкладке Editor (Редактор) необходимо включить опцию Require Variable Declaration (Требовать объявления переменных) (рис. 2). Данная опция вставляет Option Explicit в начале каждого нового модуля; однако она не обновляет старые модули. Необходимо проверить уже созданные модули и вставить в них Option Explicit.

Кроме того, могут возникать другие виды синтаксических ошибок, например:

Msggbox "Hi"

ИЛИ

EndSeb

РИСУНОК 2. Выбор опции Require Variable Declaration для выполнения объявления переменных/

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

СОВЕТ

В редакторе Visual Basic в диалоговом окне Options во вкладке Editor можно выключить опцию Auto Syntax Check (Автоматическая проверка синтаксиса). Синтаксическая проверка при этом не отключается, но исчезнет раздражающее диалоговое окно, которое всплывает при каждой синтаксической ошибке. Ошибка все равно будет отображаться, при этом код выделяется красным цветом.

В диалоговом окне Options можно модифицировать некоторые установки компилятора. Во вкладке General опция Compile on Demand (Компиляция, выполняемая по требованию) позволяет приложению выполняться быстрее, поскольку модули не компилируются до тех пор, пока не загружаются для выполнения. На современных быстродействующих компьютерах для устранения возможных ошибок рекомендуется включать эту опцию.

Кроме того, во вкладке General имеется опция Background Compile (Фоновая компиляция). Включение данной опции позволяет производить фоновую компиляцию, когда имеются свободные системные ресурсы. Опция Background Compile может повысить скорость выполнения компиляции. Чтобы воспользоваться этой возможностью, опция Compile on Demand также должна быть включена.

Очень важно скомпилировать и сохранить все модули перед распространением приложения, чтобы убедиться в том, что все синтаксические ошибки исключены. Для этого в меню необходимо выбрать пункты Debug | Compile and Save All Modules (Отладка | Скомпилировать и сохранить все модули) вне зависимости от того, загружены в данный момент все модули базы данных или нет.

Исключение логических ошибок

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

Для устранения логических ошибок рекомендуется воспользоваться мощным отладчиком Microsoft Access. Полное описание методик отладки приведено в статье «Отладка приложений Access».

Исключение ошибок рабочего цикла

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

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

Перед рассмотрением сложного обработчика ошибок приведем простой пример:

Sub Demo ( )

Dim I as Integer

On Error GoTo ErrorHandler

' Программная ошибка в этой строке кода. ExitHere:

Exit Sub ErrorHandler:

MsgBox "An error occurred"

Resume ExitHere

End Sub

Данный простой обработчик ошибок следует обычным программным соглашениям, которые описаны далее.

On Error GoTo ErrorHandler

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

СОВЕТ

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

ExitHere

Эта метка является точкой выхода для процедуры. Рекомендуется использовать только одну точку выхода в одной процедуре. Если процедура выполняется без ошибок, вызывается код ExitHere и процедура заканчивает работу. Код в ErrorHandler не выполняется, поскольку он находится в самом конце процедуры. Выполнение не доходит до этой точки в процедуре, поскольку выход из процедуры уже состоялся.

Метка ExitHere — идеальное место для вставки кода очистки. Например, можно освободить любые объектные переменные, присвоив им пустое значение, закрыть базу данных, возвратить курсор в форме песочных часов на значение, принятое по умолчанию, и включить обновление экрана.

Оператор On Error Resume обычно должен быть первым в процедуре выхода. Это необходимо, поскольку некоторые выражения очистки сами по себе могут стать причиной ошибки. Например, если сбой произошел до открытия базы данных и объектной переменной в процедуре выхода присвоено значение Nothing (Set db = Nothing), возникает ошибка.

СОВЕТ

Если процедура выполняется медленно и при этом включается/выключается курсор в форме песочных часов, (соответственно в начале и конце процедуры) необходимо быть очень осторожным, чтобы избежать проблем при возникновении ошибки. Примером кода очистки, который необходимо поместить в код ExitHere перед выходом из процедуры вне зависимости от того, возникла ошибка или нет, может служить Docmd.Hourglass false,

СОВЕТ

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

Ниже приводится пример процедуры выхода с кодом очистки:

ExitHere:

On Error Resume Next

DoCmd.Hourglass False

DoCmd.Echo True

DoCmd.SetWarnings False

Set rst = Nothing

Set db = Nothing

Exit Sub

ErrorHandler

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

Resume ExitHere

Данное выражение позволяет передать управление коду ExitHere.

Выполнение программы с обработкой ошибок

Рассмотрим изменение хода выполнения программы при наличии обработчика ошибок. Если в коде не содержится ошибок, программа выполняется так (обработчик ошибок не вызывается):

Sub Demo ( )

On Error GoTo ErrorHandler

Good code

ExitHere:

Exit Sub

ErrorHandler:

MsgBox "An error occurred"

Resume ExitHere End Sub

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

Sub Demo ( )

On Error GoTo ErrorHandler

Bad Code

ExitHere:

Exit Sub

ErrorHandler:

MsgBox "An error occurred"

Resume ExitHere

End Sub

Объект Err

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

Объект Err обладает следующими свойствами:

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

Err.Description описание ошибки.

Err.Source — объект или приложение, сгенерировавшее ошибку.

Err.HeIpFile — Путь к файлу справки Windows. Данное свойство вместе с HelpContext можно использовать для создания кнопки справки в диалоговом окне сообщения об ошибке.

Err.HelpContext — идентификационный номер соответствующей статьи в справочном файле.

Err.Last DLL Error — системный код ошибки, возвращаемый путем вызова динамически связываемой библиотеки (DLL).

Объект Err содержит два метода:

Err.Clear

Метод Clear очищает свойства объекта Err. Любое из приведенных ниже действий очищает свойства объекта Err:

• Вызов метода Clear объекта Err (Err.Clear).

• Использование любого типа оператора Resume,

• Выход из процедуры.

• Использование оператора On Error.

Err. Raise

Метод Raise генерирует ошибку рабочего цикла. Создание ошибки рабочего цикла может оказаться полезным при тестировании приложения. Можно имитировать ошибку рабочего цикла, указав код ошибки методу Raise объекта Err. Кроме того, когда приложение вызывает внешнюю динамически связываемую библиотеку (DLL), значение ошибки можно передать назад в приложение для обработки ошибки.

При генерировании ошибок можно допускать ошибки, генерируемые пользователем. Следует убедиться, что номер пользовательской ошибки является уникальным, и присвоить данный номер константе vbObjectError. Например, для создания ошибки номер 50 необходимо присвоить vbObjectError + 50 числовому аргументу:

Err.Number = vbObjectError + 50

Ниже приведен пример использования метода Raise:

Sub Demo (intNiunber)

If intNumber = 110 Then

' Создать ошибку.

Err.Raise vbObjectError + 50, "My Application", _

"The number cannot be greater than 100", _

"С:\МуАрр\МуАрр.Hip", MyContextID

End If

End Sub

Метод Raise использует пять аргументов: Number, Source, Description, HelpFile и HelpContext. (Эти аргументы такие же, как и в объекте Err.) Синтаксис должен быть таким:

Err.Raise (Number, Source, Description, HelpFile, HelpContext)

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

Err.Raise Number:= vbObjectError + 50, Description:= "My Custom Error"

СОВЕТ

Для изучения свойств и методов объекта Err необходимо воспользоваться браузером объектов. В любом модуле кода можно нажать клавишу F2, выбрать библиотеку VBA и щелкнуть на объекте Err Object в списке классов. Затем можно просмотреть все свойства и методы. Для получения справки по тому или иному свойству либо методу необходимо на-

Реагирование на возникновение ошибок

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

Ожидаемая ошибка может быть обработана различными способами:

• Окно сообщения может предупредить пользователя об ошибке.

• Окно сообщения может предоставить пользователю информацию, необходимую для исправления ошибки (например. There is no disk in the disk drive (В этом дисководе нет диска)).

• Ошибку можно проигнорировать и продолжить выполнение кода.

• Ошибку можно проигнорировать и выйти из процедуры.

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

• Можно осуществить переход в другое место кода. Приведенный ниже код иллюстрирует вышесказанное:

ErrorHandler:

Select Case Err.Number

Case 11

If MsgBox("You divided a number by zero, enter a " & _

" different number. Do you want to try again? ", _

vbQuestion + vbYesNo) = vbYes Then

Resume

Else

Resume ExitHere

End If

Case Else

MsgBox "An unexpected occurred. Error Number: " & _

Err.Number & " Error Description: " & Err.Description

Resume ExitHere

End Select

End Sub

Можно даже создать общую процедуру обработки ошибок определенного типа. Например, если просмотреть таблицу ошибок Access и Jet в файле Access and Jet Database Errors, mdb, можно заметить, что ошибки с номерами 58-76 относятся к файловым ошибкам. Сюда входят File already exists. Disk Full, Too many files и другое. Можно создать общую процедуру, работающую с данной группой ошибок, и вызывать эту процедуру из выражения Case Select обработчика ошибок:

ErrorHandler:

Select Case Err.Number

Case 58 To 76

' Общая процедура, обрабатывающая файловые ошибки.

Call FileTypeErrors

Case Else

MsgBox "An unexpected occurred. Error Number: " & _

Err.Number & " Error Description: " & Err.Description

Resume ExitHer

End Select

End Sub

Операторы Resume

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

Resume

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

Resume Next

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

Приведенная на рис. 3 диаграмма иллюстрирует ход выполнения программы в случае использования разных операторов Resume:

РИСУНОК 3. Обработка ошибок с помощью оператора Resume.

Получение дополнительной информации об ошибках

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

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

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

СОВЕТ

Объект Err не сообщает номер строки. Чтобы получить номер строки, необходимо применить функцию Ег1, которая используется в примерах данной статьи.

Name of the form or report (Имя формы или отчета). Сообщает имя формы или отчета, в котором произошла ошибка. Это всего лишь простая передача имени формы или отчета в обработчик ошибок.

Name of procedure (Имя процедуры). Сообщает имя процедуры, в которой произошла ошибка.

Name of active control (Имя активного элемента управления). Сообщает имя активного элемента управления в момент возникновения ошибки.

Value of active control (Значение активного элемента управления). Сообщает значение активного элемента управления в момент возникновения ошибки. Часто ошибка происходит только при определенных значениях, введенных в элемент управления. Если, например, ошибка возникает, когда в текстовое поле вводится значение больше 20000, данный тип ошибки можно легко идентифицировать, возвращая значение текстового поля для записи в обработчик ошибок.

ПРЕДОСТЕРЕЖЕНИЕ

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

ID of current record (ID текущей записи). Сообщает ID текущей записи формы в момент возникновения ошибки. Бывают случаи, когда некоторые записи о клиентах являются причиной большинства программных ошибок. Возвращая ID текущей записи, можно сравнить данную запись о клиенте с другими, не вызывающими ошибок. Часто причиной возникновения такой ошибки является то, что в обязательном поле отсутствуют данные.

Name of program (Имя программы). Сообщает имя приложения, в котором произошла ошибка.

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

User name (Имя пользователя). Имя зарегистрированного в данный момент пользователя. Бывают случаи, когда большинство ошибок возникает у определенных пользователей. Идентификация пользователя, у которого произошла ошибка, может оказаться весьма полезной. Часто бывает так, что проблема представляет собой не программную ошибку, а заключается в том, что пользователь плохо подготовлен. Чтобы получить имя пользователя, можно воспользоваться экраном регистрации в приложении либо зарегистрированным именем Windows 95/98/NT, вызвав API Windows.

СОВЕТ

Вызов API Windows для получения информации о текущем пользователе Windows 95/98/NT проиллюстрирован примерами кода обработчика ошибок, приведенными в данной статье. (См. свойство UserName и функцию GetUserName,)

Date and time (Дата и время). Дата и время возникновения ошибки. Эта информация полезна для анализа частоты возникновения ошибок. Простой график должен показывать, что со временем программные ошибки возникают реже.

Notes about the error (Комментарии к ошибке). Пользователи могут вводить информацию о том, что они делали в момент возникновения ошибки, или свои замечания. Эта информация может быть введена в отдельном поле или форме. Пользователи могут воспользоваться простой формой для сообщения о том, что происходило в момент появления ошибки. Необходимо сообщить пользователям, что данная информация необязательна. Возможно, одни пользователи никогда ничего не напишут о возникающей ошибке, в то время как другие захотят сообщить полезную информацию.

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

Комплексный обработчик ошибок

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

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

СОВЕТ

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

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

СОВЕТ

Для еще большей функциональности глобального обработчика ошибок рекомендуется воспользоваться Visual Basic для создания компонента, который можно использовать с любым СОМ-совместимым приложением. Такой обработчик ошибок можно использовать в Access, Word, Excel, VB и многих других приложениях. Более подробная информация об этом приведена в статье «Интеграция с Office 2000».

Модуль класса (объект) ошибки

Модуль класса с именем сЕггог в коде данной главы содержит свойства и методы, необходимые для эффективного обработчика ошибок. Объект сЕггог включает в себя весь код модуля класса. Благодаря технологии Microsoft IntelliScnsc использование данного объекта является очень простым.

СОВЕТ

Подробная информация о создании классов приводится в статье «Создание объектов с помощью модулей класса».

Свойства объекта сЕггог

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

Таблица 1. Свойства сЕггог.

Свойство

Описание

Application

Название программы, создавшей приложение (например, MS Access).

AVIFileLocation

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

Class

Имя модуля класса.

ComputerName

Имя компьютера, на котором произошла ошибка.

ComputerTotalMemory

Общий объем памяти, установленный в компьютере.

ComputerAvailableMemory

Объем доступной памяти в компьютере.

ComputerOperatingSystem

Информация об операционной системе и версии.

ComputerProcessor

Информация о процессоре компьютера.

ControlName

Имя активного элемента управления.

ControlValue

Значение активного элемента управления.

CurrentRecordID

ID текущей записи.

Description

Описание ошибки, возвращаемое объектом Егг.

EmailAddress

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

ErrorDatabase

Имя и полный путь к базе данных (например, базе данных Access или SQL Server), содержащей таблицу ошибок.

ErrorNumber

Номер ошибки, возвращаемы объектом Err.

ErrorTextFile

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

HelpContext

ID статьи файла справки, возвращаемый объектом Егг.

HelpFile

Имя и полный путь к файлу справки, возвращаемые объектом Err.

LastDIIError

Код системной ошибки для последнего вызова DLL.

Level

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

LineNumber

Номер строки оператора, в котором возникла ошибка.

Note

Примечание пользователя о том, что он делал во время возникновения ошибки.

Now

Дата и время возникновения ошибки.

Procedure

Имя процедуры

SoundFile

Имя и полный путь к звуковому файлу.

Source

Имя объекта или приложения, сгенерировавшего ошибку.

User

Имя пользователя, у которого произошла ошибка.

WaitStateFlag

Флаг, использующийся в целях установки состояния ожидания, необходимого для останова выполнения кода

UserEnterNoteFlag

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

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

Методы объекта cError

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

Таблица 2. Методы cError.

Метод

Описание

AddToErrorHandlerOutlookCalendar

Добавляет информацию об ошибке в календарь Outlook, вызвавший Error Handler.

Clear

Очищает объект Егг.

Email

При возникновении ошибки отправляет разработчику электронное сообщение с помощью Outlook.

EmailAIIErrors

Отправляет разработчику электронное сообщение с вложением, включающим всю информацию в таблице ошибок.

GetActiveControlValue

Получает значение активного элемента управления при возникновении ошибок.

MessageBox

Отображает окно сообщения с информацией об ошибке.

MsgErrorDetails

Обобщает информацию об ошибке для окна сообщения или для электронного сообщения

OfficeAssistant

При возникновении ошибки вызывает Office Assistant (помощника) и спрашивает пользователя, не желает ли он ввести примечание, относящееся к ошибке.

PlaySound

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

ProcessError

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

ShowAVIForm

Вызывает форму, включающую AVI-файл, для оповещения пользователей о возникновении ошибки

UserlnputBox

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

UserName

Получает зарегистрированное имя пользователя в Windows/Windows NT.

WaitState

Создает состояние ожидания для остановки выполнения кода.

WriteErrorToTable

Записывает информацию об ошибке в таблицу ошибок базы данных.

WriteErrorToTextFile

Записывает информацию об ошибке в текстовый файл.

Просмотр объекта cError в браузере объектов

Объект cError, приведенный в коде данной главы, содержит много свойств и методов. Для быстрого просмотра свойств и методов объекта необходимо открыть браузер объектов и выбрать модуль класса cError (рис. 4).

РИСУНОК 4. Объект cError в браузере объектов.

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

При возникновении программной ошибки обработчик ошибок в процедуре передает информацию в Объект сЕггог. Метод ProssesError определяет, как обрабатывается ошибка. Данный метод отсылает к таблице tbIErrorOptions (которая рассматривается далее в данной главе) за дополнительной информаци-ей, например, о том, вводили ли пользователи примечания об ошибке и было ли отослано электронное сообшение с информацией об ошибке. Ниже приводится код метода ProssesError:

Public Sub ProcessErrorO

Dim rst As ADODB. Recordset

Dim strSQL As String

Dim strVal As String

strSQL = "SELECT * FROM tbIErrorOptions"

' Создание набора записей ADO.

Set rst = New ADODB.Recordset

' Открытия набора записей ADO.

rst.Open strSQL, CurrentProject.Connection, adOpenKeyset, _

adLockOptimistic

Me.ErrorTextFile = rst!ErrorTextFileName

Me.UserEnterNoteFlag = rst!UserEnterNoteAboutError

Me.AVIFileLocation = CurrentProject.Path & rst!AVIFileLocation

Me.SoundFile = CurrentProject.Path & rst!SoundFile

Me.OfficeID = rst!OfficeID

Me.OfficeName = rst!OfficeName

Me.OfficePhoneNuitiber = rst!OfficePhoneNumber

Me.OfficeFaxNumber = rst!OfficeFaxNumber

If rat!PlaySound Then

' Воспроизведение звука при возникновении ошибки.

CError.PlaySound

End If

If rst!ShowOfficeAssistant Then

' Отображение помощника.

CError.OfficeAssistant

End If

If rst!ShowAVIForm Then

' Вызов AVI-формы.

CError.ShowAVIForm

' Состояние ожидания до закрытия формы.

Me.WaitState (True)

' Закрытие AVI-формы.

DoCmd.Close acForm, "frmErrorAVI", acSaveNo

End If

' Открытие формы для ввода примечания пользователя.

If Me.UserEnterNoteFlag Then

DoCmd.OpenFonn "frmErrorNote", acNormal

' Состояние ожидания до закрытия формы. Me.WaitState (True)

' Закрытие формы для примечания.

DoCmd.Close acForm, "frmErrorNote", acSaveNo

End If

If rst!ErrorsToAccessTable Then

' Запись ошибки в таблицу ошибок Access.

CError.WriteErrorToTable

End If

If rst!ErrorsToTextFile Then

' Запись ошибки в текстовый файл.

CError.WriteErrorToTextFile

End If

If rst!ErrorsToTextFile Then

' Отображение окна сообщения с информацией об ошибке.

CError.WriteErrorToTextFile

End If

If rst!AddToErrorHandlerCalendar Then

CError.AddToErrorHandlerOutiookCalendar

End If

If ret!ShowMsgBoxErrors Then

' Отображение окна сообщения с информацией об ошибке.

CError.MessageBox

End If

' Отображение формы, которая сообщает пользователю, безопасно

' ли продолжать работу. Форма автоматически закрывается

' с помощью таймера.

DoCmd.OpenForm "fnnErrorDoir", acNormal

rat.Close

Set rst = Nothing

Данный метод полагается на свойства, а также другие методы объекта сЕггог. Дополнительную информацию можно найти в коде модуля класса сЕггог.

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

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

Путем вызова нескольких методов сЕггог можно отобразить Office Assistant, AVI-форму и воспроизвести звуковой файл для уведомления пользователя об ошибке (рис. 5). В коде главы приведена AVI-форма, сообщающая пользователю об ошибке (рис. 6). Если воспользоваться модулем класса сЕггог, соответствующий код должен быть таким:

CError.OfficeAssistant cError.AVIFonn сЕггог.Sound

РИСУНОК 5 Использование Office Assistant для сообщения о возникшей ошибке.

РИСУНОК 6. Использование А VI-формы для сообщения об ошибке.

Затем можно использовать объект сЕггог для отображения формы примечания об ошибке или окна ввода, которые позволяют пользователям описать свои действия во время возникновения ошибки (рис. 7). Вполне вероятно, что многие пользователи с удовольствием воспользуются возможностью помочь разработчику. Форма Error Note указывает, что ввод примечания необязателен.

Кроме того, можно отобразить окно сообщения с подробной информацией об ошибке (рис. 8).

РИСУНОК 7. Форма позволяет пользователям ввести примечание.

РИСУНОК 8. Окно сообщения с подробной информацией об ошибке.

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

РИСУНОК 9. Сообщение пользователю о том, что можно продолжать работу.

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

Обнаружение проблем, возникающих при работе компьютеров

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

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

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

Отчетность

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

Error handler Access report (Отчет Access об обработке ошибок). Отчет обработчика ошибок в базе данных Access содержит всю информацию из таблицы ошибок для всех ошибок (рис. 10).

Email individual errors (Электронные сообщения об отдельных ошибках). Каждый раз при возникновении ошибки можно отправить подробную информацию об ошибке по электронной почте путем вызова метода Email (рис. 11).

РИСУНОК 10. Отчет Access обо всех ошибках

РИСУНОК 11. Отправка электронного сообщения об отдельной программной ошибке.

Email all errors (Электронное сообщение обо всех ошибках). Можно отправить по электронной почте всю информацию об ошибках в таблице ошибок в качестве вложения в сообщение Outlook с помощью метода EmailAllErrors. Таблица ошибок сохраняется как таблица Excel и вкладывается в электронное сообщение.

Save error information in an Access database (Сохранение информации об ошибках в базе данных Access). С помощью метода WriteErrorToTable при каждом возникновении ошибки можно записать ошибку в таблицу ошибок в базе данных Access.

• 5ave error information in a text file (Сохранение информации об ошибках в текстовом файле). С помощью метода WriteErrorToTextFile можно записать все ошибки в выбранный текстовый файл для последующего анализа.

Save error information or an Outlook calendar (Сохранение информации об ошибках в календаре Outlook). Все ошибки можно записать в календарь Outlook, так что данные могут быть отображены в различных встроенных представлениях Outlook либо в пользовательском представлении. Метод AddToErrorHandlerOutlookCalendar упрощает отправку всей информации об ошибках в календарь обработчика ошибок (рис. 12).

РИСУНОК 12. Календарь обработчика ошибок Outlook.

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

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

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

Таблица 3. Опции обработчика ошибок.

Опция

Описание

Тип данных

AccessErrorTableName

Имя таблицы Access, которая содержит информацию об ошибках.

Да/Нет

AddToErrorHandlerCalendar

Добавить ошибку и календарь обработчика ошибок.

Да/Нет

AVIFileLocation

Полный путь к AVI-файлу, использующемуся в AVI-форме.

Текст

DatabaseName

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

Текст

DatabasePath

Полный путь к базе данных.

Текст

EmailAddress

Адрес электронной почты для отправки сообщений об ошибках.

Текст

EmailErrors

Отправить сообщение при возникновении ошибки.

Да/Нет

ErrorsToAccessTable

Сохранить информацию об ошибке в таблице Access.

Текст

ErrorsToTextFile

Сохранить информацию об ошибке в текстовом файле.

Текст

PlaySound

Воспроизвести звук при возникновении ошибки.

Да/Нет

ShowAVIForm

Отобразить AVI-форму при возникновении ошибки.

Да/Нет

ShowMsgBoxErrors

Отобразить окно сообщения с информацией об ошибке.

Да/Нет

ShowOfficeAssistant

Отобразить помощник при возникновении ошибки.

Да/Нет

JoundFile

Полный путь к звуковому файлу.

Текст

UserEnterNoteAboutError

Пользователь ввел примечание.

Да/Нет

В зависимости от того, какие опции выбраны, обработчик ошибок работает по-разному. Для хранения информации об опциях обработки ошибок используется таблица, поэтому код "управляется таблицей". Вместо записи в коде новых значений опций достаточно ввести опции в таблице Error Options. Поскольку код обращается за информацией к таблице Error Options, работать таким образом гораздо удобнее.

Конечно, разработчику не нужно, чтобы пользователи вводили данные непосредственно в таблицу Access. Форма fnnErrorOptions позволяет сотрудникам обновлять и изменять опции обработки ошибок (рис. 13).

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

РИСУНОК Форма опций обработки ошибок, использующаяся для выбора соответствующих опций.

Вызовы API Windows

Все выполняемые функции комплексного обработчика ошибок нельзя запрограммировать в Microsoft Access, необходим вызов нескольких API Windows.

Обработчик ошибок получает имя пользователя, у которого произошла ошибка. Вместо того чтобы регистрировать пользователя в приложении для получения этой информации, обработчик ошибок получаст имя пользователя из API Windows. Вызов API Windows считывает зарегистрированное имя пользователя в Windows 95/98/NT.

' Вызов API Windows для получения имени пользователя.

Private Declare Function GetUserNmae Lib "advapi32.dll" Alias _

"GetUserNameA" (ByVal IpBuffer As String, nSize As Long)

При возникновении ошибки можно воспроизвести звуковой сигнал для предупреждения пользователей. Для этого также необходим вызов API Windows:

' Вызов API Windows для воспроизведения звука.

Private Declare Function sndPlaySound32 Lib "wirumn.dll" Alias _

"sndPlaySoundA" (ByVal IpszSoundName As String, ByVal uFlags As Long) As Long

Другие вызовы API Windows получают имя компьютера, информацию об объеме памяти компьютера, операционной системе и информацию о процессоре.

Ошибки в различных приложениях

В настоящее время приложения Access включают другие приложения и компоненты. Соответственно возникающие ошибки могут иметь различное происхождение. Типовое приложение Access может сгенерировать ошибку, возникшую в самом Access или в VBA, DAO, ADO либо в другом приложении, использующемся в процессе автоматизации, например, Microsoft Word. Каждое приложение имеет собственные коды ошибок, которые можно возвратить обработчику ошибок.

СОВЕТ

Таблица Access в базе данных Access and Jet dabase Errors.mdb в примерах кода данной статьи содержит номера и описание ошибок Access и Jet.

Обработка ошибок для вложенных процедур

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

Для отслеживания всех вызовов процедур существует список вызовов, который поддерживается автоматически (рис. 14). Список вызовов можно просмотреть в любой момент времени в редакторе Visual Basic, выбрав в меню пункты View | Call Stack (Сервис | Стек вызова).

РИСУНОК 14. Окно Call Stack.

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

ПРЕДОСТЕРЕЖЕНИЕ

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

Дополнительная информация об ошибках

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

Процедуры события ошибки

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

DataErr — номер ошибки, возвращаемый объектом Err. Используя данный аргумент, можно обработать соответствующий тип ошибки. Если, например, DataErr равен 11, значит, произошло деление на нуль.

Response — определяет, отображено ли сообщение об ошибке. Используя данный аргумент, можно контролировать отчетность. Чтобы проигнорировать ошибку и отобразить собственное сообщение об ошибке, необходимо воспользоваться константой acDataErrContinue. Для отображения сообщения об ошибке, принятого в Access по умолчанию, можно воспользоваться константой acDataErrDisplay.

Ниже приводится типичный пример соответствующего кода:

private Sub FormError(DataErr As Integer, Response As Integer)

Dim strMessage As String

If DataErr = 11 Then

Response = acDataErrContinue

strttoisage = "Check the value, you have divided a number by zero."

MsgBox strMessage

End If

End Sub

On Error Go To 0

Данное выражение запрещает обработку ошибок в процедуре. Кроме того, переустанавливается объект Err, при этом он имитирует вызов метода Clear объекта Err (Err.Clear). Метод Err.Clear рассмотрен ранее в данной главе.

On Error Resume Next

ПРЕДОСТЕРЕЖЕНИЕ

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

Метод AccessError

Данный метод можно использовать для возврата описания ошибки Microsoft Access. Например, если ввести ? AccessError(11) в окне Immediate (Отладка), получим Division by zero (рис. 15).

РИСУНОК 15. Использование метода AccessError в окне отладки.

Полезные функции обработки ошибок

Ниже приводятся полезные функции обработки ошибок:

IsError — используется для определения того, является ли Variant типом данных ошибки (возвращает булево значение).

CVErr — преобразовывает значение в тип данных ошибки, присваивая его переменной типа Variant.

Установка опций обнаружения ошибок

В редакторе Visual Basic (вкладка General (Общие) в меню Tools | Options (Сервис | Параметры)) можно найти некоторые дополнительные опции обработки ошибок Access (рис. 16).

РИСУНОК 16. Установка опций обнаружения ошибок.

Break on All Errors (Прерывание на всех ошибках). При возникновении ошибки код прекращает выполнение на данной строке вне зависимости от наличия обработчика ошибок. Данная опция полезна для отладки приложения, но перед распространением приложения ее необходимо отключить.

Break in Class Module (Прерывание в модуле класса). При возникновении ошибки код прекращает выполнение на данной строке только в модулях класса, если нет обработчика ошибок.

Break on Unhandled Errors (Прерывание на необрабатываемых ошибках). При возникновении ошибки код прекращает выполнение на данной строке во всех процедурах, которые не содержат обработчик ошибок.

СОВЕТ

Установку Break on All Errors в процедуре можно отменить, поместив в начале процедуры следующий код: Application.SetOption "Break On All Errors", False

Резюме

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