Обработка исключений в 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, специально для «Клуб программистов».
[QUOTE]Следует подметить, что ошибки можно обработать только в стандартных функциях Delphi, ошибки в API функциях нельзя отловить с помощью блоков try. У API функций есть свой способ узнать об ошибке или генерировать ошибки – это API функции Set/GetLastError.[/QUOTE]
Есть замечательные функции RaiseLastOSError и Win32Check, плюс ко всему, некоторые API таки генерируют исключения. Вообще, конечно, это серьезная проблема, что нет единообразия: одни возвращают true/false, другие — код ошибки, третьи — 0 или INVALID_HANDLE_VALUE или еще что либо а ошибку узнавать с помощью GetLastError, четвертые — генерируют исключение.
Ну и еще одна поправочка:
>> У каждого процесса в некоторой области памяти…
у каждого потока 😉
Спосибо за информацию.Хотя конечно эти блоки описываются во многих книгах по программированию на Delphi.
Не проще ли обработывать Exception????
Доброго времени суток уважаемые господа.
Хотел поблагодарить автора за полезную статью. Как раз мы проходили на паре простейшие исключения, и генерацию их.
Спасибо.
Как говориться пищи исчо!!! 🙂
Да не могу я сладить с этими исключениями. Беру любой пример из инета, из хелпа или из книги. Вставляю в стандартную функцию отработки нажатия клавиши. При компиляции ошибок не даёт, а except отрабатывать не хочет. Готов переписываться и хочу научиться с ними работать.
Вооо, наконец-то я нашла одну немаловажную мелочь «Код, находящийся после строки, вызвавшей исключение, выполняться не будет», спасибо автору! 🙂