Реферат: Централизованная обработка исключений

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
Бесплатно скачать Реферат: Централизованная обработка исключений