Реферат: Централизованная обработка исключений
int trylevel;
// указатель на следующую запись
int _ebp;
};
В этой структуре handler является процедурой обработки исключения. Прототип этой функции приведен ниже:
typedef int (*SEHHandler)(PEXCEPTION_RECORD, PEXCEPTION_REGISTRATION, PCONTEXT, void*); |
Как видите, функция обработчика исключения принимает 4 параметра. Первый параметр имеет тип PEXCEPTION_RECORD – это указатель на структуру, содержащую информацию об исключении. Вы можете найти объявление этой структуры в заголовочном файле winnt.h:
typedef struct _EXCEPTION_RECORD { DWORD ExceptionCode; DWORD ExceptionFlags; _EXCEPTION_RECORD *ExceptionRecord; PVOID ExceptionAddress; DWORD NumberParameters; ULONG_PTR ExceptionInformation [EXCEPTION_MAXIMUM_PARAMETERS]; } EXCEPTION_RECORD; |
Описание наиболее значимых полей этой структуры приведено ниже:
ExceptionCode – тип исключения.
ExceptionFlags – флаг исключения.
ExceptionAddress – адрес участка кода, где возникло исключение.
Второй параметр функции содержит в себе указатель на структуру PEXCEPTION_REGISTRATION. Ее описание и назначение было приведено выше.
Третий параметр указывает на переменную типа PCONTEXT и несет информацию о состоянии регистров во время исключения.
Таким образом, механизм обработки исключений становится более или менее ясным, т.е. когда в приложении возникает исключение, операционная система берет текущий указатель по адресу fs:[0] и просматривает список обработчиков в поисках нужного обработчика исключения. Если обработчик найден, она передает ему управление. В противном случае операционная система выполняет свой обработчик, который вызывает функцию UnhandledExceptionFilter. Значит, для получения управления в случае возникновения необработанного исключения, нужно зарегистрировать свой обработчик и расположить его в вершине этого списка. Но мир программирования не был бы таким интересным, если бы все было так просто! Давайте пройдем дальше и посмотрим, что происходит во время старта приложения, и какую роль в обработке исключений играет runtime-библиотека.
Старт приложения и инициализация runtime
Когда операционная система загружает приложение, она считывает содержимое файла с диска в память, загружает все необходимые для работы приложения внешние библиотеки и инициализирует таблицу импорта адресами реальных функций. После этого загрузчик передает управление на точку входа приложения. В случае С++-приложений, написанных с использованием Microsoft Visual Studio 6.0 (7.x, 8.0), управление передается функции WinMainCRTStartup или wWinMainCRTStartup, в зависимости от версии runtime-библиотеки – UNICODE или Multi-Byte Character Set (MBCS). Эта функция подготавливает приложение к работе, инициализирует runtime, выполняет конструкторы всех статических переменных и передает управление на точку входа, определенную разработчиком. Если внимательно рассмотреть эту функцию, можно увидеть, что инициализация пользовательских статических переменных и передача управления на пользовательскую точку входа осуществляется внутри блока __try … __except. Углубившись в исследование фильтра исключений runtime-библиотеки, я обнаружил, что в случае возникновения необработанного исключения он вызывает функцию UnhandledExceptionFilter.
Функция UnhandledExceptionFilter находится в библиотеке kernel32.dll и присутствует в Windows, начиная с версии Windows 95/NT. Назначение этой функции, как видно из названия - обработка необработанных исключений и завершение приложения. В зависимости от того, как запущено приложение, UnhandledExceptionFilter ведет себя по-разному. Так, если приложение находится под отладкой, она передает управление отладчику, в противном случае она выводит диалоговое окно «Application Error». Значит, для обработки необработанных исключений, следует установить свой обработчик не на вершину списка обработчиков, как казалось раньше, а перед обработчиком Runtime библиотеки.
Установка обработчика верхнего уровня
Давайте немного отдохнем и суммируем все сказанное выше. SEH – это системный сервис, в котором унифицирован механизм обработки исключений, все обработчики текущего потока регистрируются в списке регистрации обработчиков исключений. Если в функции встречается конструкция __try … __except, то создается код, который регистрирует новый обработчик исключения и помещает информацию о нем в стек. Во время завершения функции (а точнее, после того, как управление вышло из секции __try), функция разрегистрирует обработчик. Значит, если к текущему моменту в стеке находится три функции, каждая из которых установила свой обработчик исключения, то в списке обработчиков исключения должно находиться по крайней мере три обработчика, а в стеке должны находиться три записи об обработчиках исключений. Информация о текущем обработчике доступна по адресу fs:[0]. Runtime-библиотека регистрирует свой обработчик исключений, который (если исключение не обрабатывается приложением) вызывает функцию UnhandledExceptionFilter, после чего приложение завершается с выводом диалогового окна «Application Error».
Теперь настало время написать код, который бы использовал сказанное выше и подтвердил правильность наших суждений. Давайте напишем простую функцию, которая бы пробегала по всем зарегистрированным обработчикам и выводила информацию о них на экран. Код функции приведен ниже:
void zWalkThroughSEH() { _EXCEPTION_REGISTRATION * pVCExcRec; __asm mov eax, FS:[0] К-во Просмотров: 279
Бесплатно скачать Реферат: Централизованная обработка исключений
|