Назначив этим обработчикам наши процедуры обработки, мы получим контроль над потоком исклчений и вызовов Assert.
Использование компонента (назовем его TglExceptionHandler) можно проиллюстрировать несколькими примерами:
Пример 1 Вызов Assert будет обработан и сохранен в протокол,
т.к. TglExceptionHandler перехватывает вызовы Assert:
{$ASSERTIONS ON}
procedure LoadSettings(FileStream: TFileStream);
begin
assert(Assigned(FileStream), 'Потоковый объект должен быть создан ранее');
end;
Пример 2 Вызов Assert будет обработан и сохранен в протокол с текстом исключения и GUID:
try
x := StrToInt(sSomeStringParameter);
except
on E: Exception do Assert(Assigned(E), E.Message +
'{1CC90D41-B651-11D4-AAE3-000000000000}');
end;
Пример 3 Возобновление исключения напрямую через компонент.
Исключение будет обработано и сохранено в протокол,
пользователь увидит понятное сообщение об ошибке:
eh: TglExceptionHandler;
...
try
ConvertDataToXML(); // некий вызов
except
on E: Exception do eh.Raise_(E, 'Ошибка вызова конвертера XML',
'{1CC90D41-B651-11D4-AAE3-000000000000}');
end;
end;
Вариант использования, приведенный во втором примере, выглядит очень неплохо, так как включает в себя больший набор информации для диагностирования ошибки и возвращает номер строки в исходном коде. Есть только одно неудобство: пользователь программы получает техническое сообщение об ошибке, как правило, на английском языке. Да и исподники постоянно меняются, номер строки и имя модуля - ненадежная информация. Третий вариант не включает информации о строке в исходном коде, но GUID позволяет однозначно локализовать источник ошибки и отображает понятное для пользователя сообщение, что очень важно.
Известно, что если пользователь не понимает, что происходит, то он начинает сильно нервничать. Мы, как разработчики, в этом смысле должны по возможности беречь покой пользователя, так как в конечном итоге это и наш покой. Отсюда делаем вывод, что третий вариант следует признать наилучшим (рис. 2).
Резюме правил обработки исключений с помощью класса TglExceptionHandler
Использование
Компонент класса TglExceptionHandler следует выносить на главную форму или на форму, создаваемую в первую очередь. Можно, конечно, добавить его на любую форму, но в этом случае до создания этой формы ошибки обрабатываться не будут. При добавлении компонента в DataModule в его обработчике OnCreate нужно добавить строку glExceptionHandler.Refresh;.
У компонента есть два перегруженных метода протоколирования и возобновления ошибки Raise_:
ID - уникальный идентификатор источника ошибки (GUID); генерируется в Delphi IDE нажатием Ctrl+Shift+G; ID позволит однозначно идентифицировать место ошибки.
В случае использования первого варианта вызова пользователь увидит сообщение Message, а в файл протокола будет записана подробная информация + ID. На основании ID можно будет однозначно найти место ошибки.
В случае использования второго синтаксиса вызова пользователь увидит то же самое, что он увидел бы при отсутствии обработчика + ID. В файл протокола также будет записана подробная информация + ID.
Первый вариант следует использовать для участков кода, когда критическая ситуация прогнозируема. Например, конвертация введенной текстовой строки в число. В этом случае пользователь получит понятное ему сообщение (ведь он не обязан знать технический английский) и введет корректные данные. Возникает вопрос: зачем протоколировать такие сбои, как ввод неверных данных? Быть может и не стоит, можно упростить обработку, но статистика ошибок пользователя, которая может быть потом получена из протокола - тоже ценная информация.
Второй вариант рекомендуется использовать для всех (или почти всех) процедур и обработчиков. В этом случае пользователь программы получит кроме малопонятного ему сообщения об ошибке еще и код, по которому программист сможет быстро найти источник ошибки.
Пример использования:
... some code ...
EH: TglExceptionHandler;
... some code ...
try
Database.Connected := true; //...критический участок кода
except
on E:Exception do EH.Raise_(E, 'Не удается соединиться с сервером' + Database.DatabaseName,
Edit.Text := spSomeStoredProc.FlieldByName('поля с этим именем может и не быть!').AsString;
... some code ...
except
on E:Exception do EH.Raise_(E, '{013D4094-D745-11D4-BBFB-0080C86E0E67}')
end;
Если следовать приведенным выше рекомендациям, то число сообщений на непонятном техническом английском, получаемых пользователем, будет сведено к минимуму, а разработчики программы смогут быстро и однозначно идентифицировать место ошибки по уникальному коду.
В библиотеке Globus.lib рассмотренный компонент обработки исключений умеет создавать лог ошибок, записывая в него конфигурацию клиентской системы, протоколировать ошибки, отправлять уведомления через MailSlot и даже создавать скриншоты экрана приложения при сбое (для особо тяжелых случаев). Также компонент может очень быть очень удобен для ведения протокола работы программы. Стоит ли говорить, что код компонента снабжен подробнейшими комментариями, которые ответят на вопросы, не нашедшие отражения в материале этой статьи.
Протокол обработки выглядит так:
exception log
- заголовок
ExeModule= C:\ Projects\Spell\Source\spell.exe
OSPlatform= NT
CPUKind= 15
CPUName= P15
TotalPhys= 267894784
AvailPhys= 32600064
TotalPageFile= 646012928
AvailPageFile= 395452416
TotalVirtual= 2147352576
AvailVirtual= 2017599488
ColorDepth= 32
SystemFont= SmallFont
VRefreshRate= 85
GraphicResolution= 1152x864
- протокол
Computer= SATELLITE
User= arakh
Datetime= 04.04.2002 17:50:20
ID= patch cmdAdd_PackQuantity upplied
Exception class= EDatabaseError
ExceptAddr= 004A51EC
Computer= SAN
User= chudin
Datetime= 26.06.2002 19:21:41
ExceptionMessage= tblClients: Не могу выполнить эту операцию для закрытого набора данных (dataset)
ID= {B6EE9D6D-5C34-4F09-884D-E0620566C192}
Exception class= EUpdateClientsError
ExceptAddr= 004A5245
Computer= SAN
User= chudin
Datetime= 26.06.2002 20:31:00
ID= {FBB12FD2-F2D3-11D5-BCAF-0080C86E0E20}
ExceptionMessage= Поле 'INN' не может быть изменено
...
Преимущества описанного подхода
Самое важное, чего удается достичь с использованием описанного подхода к обработке исключений - это явное упрощение локализации ошибок в уже распространенных конечным пользователям программных продуктах. Также программа ведет себя более дружественно к пользователю при сбоях, т.к. для наиболее критических участков кода мы позаботились о выводе пользователю понятного сообщения на родном языке.
Рассмотренный подход к обработке ошибок применяется автором статьи и рядом других разработчиков уже более двух лет и использован более чем в десятке программных проектов.
Функциональность работы с удаленной обработкой ошибок от клиентских приложений в реальном времени прекрасно рассмотрена в статье Ильдара Даутова на сайте "Королевство Дельфи" (http://www.delphikingdom.com/mastering/errors.htm). Рекомендуем прочитать этот очень полезный материал, он - первоисточник такого подхода.
Компонент TglExceptionHandler входит в состав библиотеки Globus VCL Extention Library. Эта библиотека создается автором этой статьи начиная с 1998 года и распространяется бесплатно с открытыми исходными кодами. Содержит около 30 визуальных и 20 невизуальных компонентов. Краткую информацию о библиотеке, а также ее дистрибутив можно найти тут: http://www.siteBuilder.ru/GlobusLib.htm
3.7 Формирование и вывод отчетов
3.7.1 Назначение и вывод отчетов. Защита отчета от несанкционированного доступа
Отчет – это форматированное представление данных, которое выводится на экран, в печать или файл. Они позволяют извлечь из базы нужные сведения и представить их в виде, удобном для восприятия, а также предоставляют широкие возможности для обобщения и анализа данных.
При печати таблиц и запросов информация выдается практически в том виде, в котором хранится. Часто возникает необходимость представить данные в виде отчетов, которые имеют традиционный вид и легко читаются. Подробный отчет включает всю информацию из таблицы или запроса, но содержит заголовки и разбит на страницы с указанием верхних и нижних колонтитулов.
Microsoft Access отображает в отчете данные из запроса или таблицы, добавляя к ним текстовые элементы, которые упрощают его восприятие.
К числу таких элементов относятся:
· Заголовок. Этот раздел печатается только в верхней части первой страницы отчета. Используется для вывода данных, таких как текст заголовка отчета, дата или констатирующая часть текста документа, которые следует напечатать один раз в начале отчета. Для добавления или удаления области заголовка отчета необходимо выбрать в меню Вид команду Заголовок/примечание отчета.
· Верхний колонтитул. Используется для вывода данных, таких как заголовки столбцов, даты или номера страниц, печатающихся сверху на каждой странице отчета. Для добавления или удаления верхнего колонтитула необходимо выбрать в меню Вид команду Колонтитулы. Microsoft Access добавляет верхний и нижний колонтитулы одновременно. Чтобы скрыть один из колонтитулов, нужно задать для его свойства Высота значение 0.
· Область данных, расположенная между верхним и нижним колонтитулами страницы. Содержит основной текст отчета. В этом разделе появляются данные, распечатываемые для каждой из тех записей в таблице или запросе, на которых основан отчет. Для размещения в области данных элементов управления используют список полей и панель элементов. Чтобы скрыть область данных, нужно задать для свойства раздела Высота значение 0.
· Нижний колонтитул. Этот раздел появляется в нижней части каждой страницы. Используется для вывода данных, таких как итоговые значения, даты или номера страницы, печатающихся снизу на каждой странице отчета.
· Примечание. Используется для вывода данных, таких как текст заключения, общие итоговые значения или подпись, которые следует напечатать один раз в конце отчета. Несмотря на то, что в режиме Конструктора раздел "Примечание" отчета находится внизу отчета, он печатается над нижним колонтитулом страницы на последней странице отчета. Для добавления или удаления области примечаний отчета необходимо выбрать в меню Вид команду Заголовок/примечание отчета. Microsoft Access одновременно добавляет и удаляет области заголовка и примечаний отчета
В Microsoft Access можно создавать отчеты различными способами:
· Конструктор
· Мастер отчетов
· Автоотчет: в столбец
· Автоотчет: ленточный
· Мастер диаграмм
· Почтовые наклейки
Мастер позволяет создавать отчеты с группировкой записей и представляет собой простейший способ создания отчетов. Он помещает выбранные поля в отчет и предлагает шесть стилей его оформления. После завершения работы Мастера полученный отчет можно доработать в режиме Конструктора. Воспользовавшись функцией Автоотчет, можно быстро создавать отчеты, а затем вносить в них некоторые изменения.
Для создания Автоотчета необходимо выполнить следующие действия:
· В окне базы данных щелкнуть на вкладке Отчеты и затем щелкнуть на кнопке Создать. Появится диалоговое окно Новый отчет.
· Выделить в списке пункт Автоотчет: в столбец или Автоотчет: ленточный.
· В поле источника данных щелкнуть на стрелке и выбрать в качестве источника данных таблицу или запрос.
· Щелкнуть на кнопке ОК.
· Мастер автоотчета создает автоотчет в столбец или ленточный (по выбору пользователя), и открывает его в режиме Предварительного просмотра, который позволяет увидеть, как будет выглядеть отчет в распечатанном виде.
· В меню Файл щелкнуть на команде Сохранить. В окне Сохранение в поле Имя отчета указать название отчета и щелкнуть на кнопке ОК.