Книга знаний

Рекламное место пустует
1С:Предприятие / Приемы программирования / Внешние компоненты

Обеспечение стабильной работы внешних компонент на Delphi

При работе с внешними компонентами рекомендуется тщательно отрабатывать исключительные ситуации - иначе 1С:Предприятие будет "обрушиваться" - порой, вместе с введенными пользователем данными - по мере наступления каких-либо проблемных ситуаций. Автор статьи: romix | Редакторы: pectopatop
Последняя редакция №6 от 13.10.07 | История
URL: http://kb.mista.ru/article.php?id=100

Ключевые слова: внешняя компонента, исключение, ShowErrorLog, Exception, RaiseLastOSError, Delphi, Рихтер


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

Я обрабатываю исключительные ситуации так:

  try
    //...
    //Фрагмент кода, где возможна ошибка
    //...
  except
     on E:Exception do begin
       ShowErrorLog('Ошибка чтения данных COM-порта: '+E.Message);
     end;
  end;


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

Можно делать вложенные друг в друга блоки Try:

    Try
        //Фрагмент1 кода, где возможна ошибка. Начало
        Try
            //...
            //Фрагмент2 кода, где возможна ошибка
            //...
        Except
            //Обработки ошибок нет
        End;
        //Фрагмент1 кода, где возможна ошибка. Окончание
    Except
        ShowMessage('ОШИБКА!');
    End;


Тогда ошибка, возникшая в самом внутреннем блоке, вызовет исключение его же (самого внутреннего) блока. Если в данном Except .. End не будут записаны какие-либо действия по обработке ошибки, то ее обработка передается на объемлющий блок Try .. Except .. End, и так далее, вплоть до самого верхнего уровня. Если и на самом верхнем уровне вашей программы не будет найдена обработка ошибки, то ею займется среда выполнения, она выдаст стандартное окно ошибки, как будто вы и не использовали вовсе блоков Try, за исключением случая, когда ваш блок Try самого верхнего уровня будет иметь вид:

  try
    //...
    //Фрагмент кода, где возможна ошибка
    //...
  except
  end;


То есть, если между Except и End нет никаких операторов, то обработка ошибки заключается в простом умолчании о ней во время выполнения: вы попытались сделать некоторые действия, они не осуществились, ну и Бог с ними. =)

Кроме блоков Try .. Except .. End существует другая их модификация, которая тоже может быть полезной, - блок Try .. Finally .. End. То есть вместо ключевого слова Except следует ключевое слово Finally. Тогда код записанный между Finally и End будет выполнен наоборот лишь в том случае, если код между Try и Finally выполнился успешно (т.е. без ошибок).

Метод ShowErrorLog, используемый в примере выше, выдает ошибку "красненьким" в окне сообщений 1С.

procedure AddInObject.ShowErrorLog(fMessage:WideString);
var
  ErrInfo: PExcepInfo;
begin
  If Trim(fMessage) = '' then Exit;
  New(ErrInfo);
  ErrInfo^.bstrSource := c_AddinName;
  ErrInfo^.bstrDescription := fMessage;
  ErrInfo^.wCode:=1006;
  ErrInfo^.sCode:=E_FAIL; //генерация исключения в 1С
  iError.AddError(nil, ErrInfo);
end;


Поле sCode следует установить в значение E_FAIL, если ошибка должна остановить (прервать) выполнение кода на языке 1С, либо другое значение в противном случае (эта особенность явно указана в статье на диске ИТС и не слишком явно, если вообще указана - в "Технологии создания внешних компонент" от 1С).

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

  if not GetCommState(hCom,dcb) //uses Windows
    then RaiseLastOSError;


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

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

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

Полезные сведения об обработке исключительных ситуаций (на примере С++) пишет известный автор Дж.Рихтер в своей книге - супербестселлере "Windows для профессионалов", которая настоятельно рекомендуется к прочтению.

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

Систематическое применение Exception.Create("Текстовое сообщение"), или же вызов исключений конкретного типа при любых ошибках или недочетах входных данных позволит сделать программу безошибочной, легко отлаживаемой и "самотестируемой". Можно даже утверждать, что чем больше операторов вызова исключений - тем лучше. Вы заметите, как легко искать и отлаживать код, если "сторожа"-RaiseException, которые о них вам сообщают, расставлены во всех ключевых точках вашей внешней компоненты.
Закладка

Описание | Рубрикатор | Поиск | ТелепатБот | Захваченные статьи | Установки | Форум
© Станислав Митичкин (Волшебник), 2005-2021 | Mista.ru

Яндекс.Метрика