» Обработка исключений в Delphi Borland Delphi. . . Блог программистов


Блог программистов




200711 Сен

Обработка исключений в Delphi

   Здравствуйте уважаемые «дельфисты» и им сочувствующие. Сегодня я вам расскажу про обработку исключений в программах на Delphi. Техника, описанная мной позволяет почти полностью контролировать выполнение сомнительного кода, который может и не сработать в самый критичный момент. Данная статья в первую очередь ориентирована на «чайников».

   Начнём сначала (это низкоуровневая часть этой статьи, кому не интересно тот может не читать). В Windows исключения обрабатываются с помощью техники SEH. Расшифровывается она так – Structured Exception Handling, т.е. структурированная обработка исключений. Суть её вот в чём. У каждого потока в некоторой области памяти (обычно она указывается сегментным регистром fs) находится связанный список, в каждом элементе которого содержатся по два указателя: один указывает на обработчик исключения, второй указывает на следующий элемент. Таким образом, получается цепочка указателей обработчики (первый элемент находится по адресу [fs]:0). При возникновении исключения (например: деление на ноль, обращение к несуществующей (невыделенной) памяти, неправильная операция над числами, неверное преобразование и т.д.) вызывается первый обработчик, он может обработать исключение и вернуть результат EXCEPTION_CONTINUE_EXECUTION т.е. «всё нормально», или если оно не может его обработать или оно предназначено для обработки других исключений оно возвращает результат EXCEPTION_CONTINUE_SEARCH, то управление будет передано следующему обработчику и так до тех пор, пока исключение не будет обработано (если уж никто не смог обработать исключение, то я думаю, последний обработчик додумается завершить приложение).
   Теперь ближе к делу. В Delphi техника SEН реализуется с помощью блока try…except/finally…end. Общий формат этих блоков такой:
    try
<код>
    except
<что будет выполнено если будет исключение>
    end

либо:
    try
<код>
    finally
<что будет выполнено в любом случае>
    end

   В втором случае видно что в цепочку обработчиков SEH будет добавлен пустой обработчик, а в первом случае в цепочку обработчиков будет добавлен указатель на блок except…end. В блоке, который следует после except можно обработать исключение, можно просто вывести сообщение об ошибке, а можно и ничего не делать. При возникновении ошибки в основном блоке управление сразу же передаётся коду, который находится в блоке except. Код, который находится после строки, которая вызвала исключение не выполнится. Если основной код слишком большой, и могут возникать различные ошибки, то можно с помощью блока on…do узнать какое именно исключение произошло. Например:
   try
       d:=56/0;
       x:=round(d);
   except
       on EInvalidOp do
           ShowMessage(‘деление на ноль’)
       else
           ShowMessage(‘другая ошибка’);
   end;

Можно получить детальную информацию об исключении, объявив в блоке on…do переменную требуемого класса и потом её использовать, например:
   try
       d:=56/0;
       x:=round(d);
   except
       on Excp : EInvalidOp do
           ShowMessage(‘ошибка под названием — ‘+Excp.Message)
       else
           ShowMessage(‘Другая ошибка’);
   end;

Можно сгенерировать исключение с помощью оператора raise, например:
   type
       MyClass = class (Exception);
………
   begin
//more code
      raise MyClass.Create(‘любой текст’);

или можно воспользоваться уже существующим классом, например
   raise EZeroDivide.Create(‘текст’);
   Информацию о классах исключений можно получить, набрав в справке Delphi «VCL exception classes» (там конечно не все, но для начала хватит).
   Следует подметить, что ошибки можно обработать только в стандартных функциях Delphi, ошибки в API функциях нельзя отловить с помощью блоков try. У API функций есть свой способ узнать об ошибке или генерировать ошибки – это API функции Set/GetLastError.
   Вот наверно и всё. Это был rpy3uH, специально для «Клуб программистов».

Комментарии

  1. Slovinsky
    Октябрь 30th, 2007 | 13:12

    [QUOTE]Следует подметить, что ошибки можно обработать только в стандартных функциях Delphi, ошибки в API функциях нельзя отловить с помощью блоков try. У API функций есть свой способ узнать об ошибке или генерировать ошибки – это API функции Set/GetLastError.[/QUOTE]

    Есть замечательные функции RaiseLastOSError и Win32Check, плюс ко всему, некоторые API таки генерируют исключения. Вообще, конечно, это серьезная проблема, что нет единообразия: одни возвращают true/false, другие — код ошибки, третьи — 0 или INVALID_HANDLE_VALUE или еще что либо а ошибку узнавать с помощью GetLastError, четвертые — генерируют исключение.

    Ну и еще одна поправочка:
    >> У каждого процесса в некоторой области памяти…
    у каждого потока 😉

  2. Demondragonclik
    Декабрь 8th, 2007 | 14:12

    Спосибо за информацию.Хотя конечно эти блоки описываются во многих книгах по программированию на Delphi.

  3. Декабрь 25th, 2007 | 20:55

    Не проще ли обработывать Exception????

  4. Март 13th, 2008 | 21:58

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

  5. Валерий
    Сентябрь 22nd, 2009 | 13:47

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

  6. Katik
    Октябрь 14th, 2009 | 18:44

    Вооо, наконец-то я нашла одну немаловажную мелочь «Код, находящийся после строки, вызвавшей исключение, выполняться не будет», спасибо автору! 🙂