Мир объектов Excel 2000

         

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


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

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

Вот как выглядит модернизованная процедура, организующая соединение:

Public Sub ConnectionWithEvents() 'Создание соединения с тестовой базой данных Access 'Объект с событиями Dim imEvCon As New MyEventsADO ' Связывание объекта с событиями Set imEvCon.EvCon = Con1 Dim strConnStr As String If Con1.State = adStateOpen Then Con1.Close 'закрыть соединение 'Вариант 1 'Конфигурирование соединения Con1 'Con1.Provider = "Microsoft.jet.oledb.4.0" Con1.Provider = "MSDASQL"

Con1.ConnectionString = "Data Source=c:\!O2000\DsCd\Ch14\dbPP2000.mdb" Con1.CursorLocation = adUseClient 'Открытие соединения On Error GoTo Check Con1.Open Exit Sub Check: 'Повтор операции соединения Resume End Sub

В этой процедуре следует обратить внимание на следующие моменты:

  1. "Правильный" Провайдер, позволяющий работать с базой данных Access закомментирован. Указан Провайдер "MSDASQL", - его вызов приведет к ошибке при установлении соединения. Для удобства восприятия текст этой строки и других строк, требующих внимания, подсвечен.
  2. Чтобы иметь возможность написать обработчики событий, возникающих при соединении, введен соответствующий объект imEvCon класса MyEventsADO, о создании которого я говорил выше.
  3. Предусмотрена возможность обработки возникающих ошибок. О том, как исправить возникающую ошибку, скажу чуть ниже.

В класс MyEventsADO я добавил следующий обработчик события ConnectComplete:

Private Sub EvCon_ConnectComplete(ByVal pError As ADODB.Error, _ adStatus As ADODB.EventStatusEnum, _ ByVal pConnection As ADODB.Connection) 'Печать параметров обработчика события MsgBox "Обработчик события ConnectComplete! " & vbCrLf & _ "Строка соединения = " & _ pConnection.ConnectionString & vbCrLf & _ "Статус выполняемой операции = " & adStatus 'Печать параметров объекта Error If Not (pError Is Nothing) Then With pError MsgBox "Описание ошибки:" & .Description & vbCrLf & _ "Код Провайдера:" & .NativeError & vbCrLf & _ "Константа, идентифицирующая ошибку:" & .Number & vbCrLf & _ "Имя объекта:" & .Source & vbCrLf & _ "ANSI SQL код:" & .SqlState End With End If If adStatus = adStatusErrorsOccurred Then 'Исправление ошибки pConnection.Provider = "Microsoft.jet.oledb.4.0" End If 'Анализ коллекции Errors Dim myErr As Error Dim MyCon As Connection Set MyCon = pConnection Debug.Print MyCon.Errors.Count For Each myErr In MyCon.Errors Debug.Print myErr.Description Next myErr MyCon.Errors.Clear Debug.Print MyCon.Errors.Count MyCon.Errors.Refresh Debug.Print MyCon.Errors.Count For Each myErr In MyCon.Errors Debug.Print myErr.Description Next myErr End Sub


Прокомментирую работу этой процедуры:

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


    Рис. 6.3.  Окна сообщений, появляющиеся при установлении соединения

    Обратите внимание, статус показывает, что в момент соединения возникла ошибка, поэтому строка соединения короткая и не содержит информации, добавляемой Провайдером.
  • Следующая часть обработчика ConnectComplete работает тогда, когда обработчику передается объект Error. В функции MsgBox, окно которой также показано на рис. 6.3, формируется информация о свойствах объекта Error, в частности, описание ошибки показывает, что ODBC-Провайдер не сумел найти источник данных.
  • В обработчике события "исправляется" ошибка и устанавливается "правильный" Провайдер. Конечно, в реальной ситуации для этого мог понадобиться диалог с пользователем, но я решил упростить демонстрационный пример. В процедуре есть еще одна часть, связанная с выдачей отладочной информации, но о ней чуть позже, а пока скажу, что произойдет по окончании работы обработчика событий. Понятно, что когда управление вернется в процедуру ConnectionWithEvents в оператор Con1.Open, вызвавший событие, то из-за возникновения ошибки в охраняемом блоке управление будет перехвачено и передано на метку Check. Оператор Resume заставит повторить открытие соединения, но теперь уже свойства соединения заданы корректно. Снова работает процедура ConnectComplete, но в ситуации, когда ошибка не возникает. В этот раз будет работать только первая функция MsgBox, которая уведомит о нормальном завершении и выдаст подробную информацию в строке соединения.
  • В заключительной части процедуры ConnectComplete выводится на печать отладочная информация о коллекции Errors объекта Connection. Я специально поместил ее в эту процедуру, чтобы обратить Ваше внимание на тот факт, что при обработке события Complete коллекция Errors объекта Connection еще не сформирована, она создается лишь после завершения работы этой процедуры. Поэтому, как ни странно, но при первом вызове, когда ошибка есть, коллекция Errors пуста, а во втором вызове, когда ошибки нет, коллекция существует, сохраняя историю первого вызова. Заметьте, по этой причине было бы разумнее с содержательной точки зрения поместить эту группу операторов в блок с меткой Check. Иллюстрацией к этому тексту являются результаты отладочной печати:
0 0 0 1 [Microsoft][ODBC Driver Manager] Data source name not found and no default driver specified 0 0



Еще одна ошибка, которую я решил смоделировать, возникает при работе с объектом Recordset, - некорректно формируется значение поля при изменении записи. К уже имеющемуся обработчику события WillChangeField я добавил обработчик события ChangeFieldComplete. Поскольку общая схема экспериментов остается такой же, как и для объекта Connection, то я приведу тексты процедур без дополнительных комментариев. В уже описанной процедуре CreateEvents я заменил оператор

!Цена = !Цена * 2

на оператор

!Цена = "По Договоренности"

Эта замена приводит к ошибке несоответствия типов. Вот текст обработчика события ChangeFieldComplete:

Private Sub EvRst_FieldChangeComplete(ByVal cFields As Long, _ ByVal Fields As Variant, ByVal pError As ADODB.Error, _ adStatus As ADODB.EventStatusEnum, _ ByVal pRecordset As ADODB.Recordset) 'Печать параметров обработчика события MsgBox "Номер поля = " & cFields & vbCrLf & _ "Значение поля = " & Fields(cField) & vbCrLf & _ "Позиция записи в наборе = " & _ pRecordset.AbsolutePosition & vbCrLf & _ "Статус выполняемой операции = " & adStatus 'Печать параметров объекта Error If Not (pError Is Nothing) Then With pError MsgBox "Описание ошибки:" & .Description & vbCrLf & _ "Код Провайдера:" & .NativeError & vbCrLf & _ "Константа, идентифицирующая ошибку:" & .Number & vbCrLf & _ "Имя объекта:" & .Source & vbCrLf & _ "ANSI SQL код:" & .SqlState End With End If 'Анализ коллекции Errors Dim myErr As Error Dim MyCon As Connection Set MyCon = pRecordset.ActiveConnection Debug.Print MyCon.Errors.Count For Each myErr In MyCon.Errors Debug.Print myErr.Description Next myErr

End Sub

Вот как выглядит серия появляющихся окон функции MsgBox, вызываемой в процедурах: CreateEvents, WillChangeField, ChangeFieldComplete, при попытке изменить поле "Цена":


Рис. 6.4.  Серия окон, появляющихся при попытке изменить значение поля.

Возможно, полезно взглянуть и на информацию, появляющуюся в окне отладки:

0 1 Operation was canceled. 1 Operation was canceled. 1 Multiple-step operation generated errors. Check each status value.


Содержание раздела