Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Создание эффективных приложений для Windows Джеффри Рихтер 2004 (Книга).pdf
Скачиваний:
385
Добавлен:
15.06.2014
Размер:
8.44 Mб
Скачать

Значение

0 = успех 1 = информация 2

0 = Microsoft 1 =

Должен быть 0 (см

Определяется

Определяется

 

= предупреждение 3 =

пользователь

таблицу ниже)

Microsoft

Microsoft или

 

ошибка

 

 

 

пользовате лем

Таблица 24-1, Поля кода ошибки

На сегодняшний день определены такие коды подсистемы.

Код подсистемы

Значение

Код подсистемы

Значение

 

 

 

 

FACILITY_NULL

0

FACILITY_CONTROL

10

 

 

 

 

FACILITY_RPC

1

FACILITY_CERT

11

 

 

 

 

FACILITY_DISPATCH

2

FACILITY_INTERNET

12

 

 

 

 

FACILITY_STORAGE

3

FACILITY_MEDIASERVER

13

 

 

 

 

FACILITY_ITF

4

FACILITY_MSMQ

11

 

 

 

 

FACILITY_WIN32

7

FACILITY_SETUPAPI

15

 

 

 

 

FACILITY_WINDOWS

8

FACILITY_SCARD

16

 

 

 

 

FACILITY_SECURITY

9

FACILITY_COMPLUS

17

 

 

 

 

Разберем на части, например, код исключения EXCEPTION_ACCESS_VIOLATlON. Если Вы посмотрите его значение в файле WinBase.h, то увидите, что оно равно 0xC0000005:

С 0 0 0 0 0 0 5 (в шестнадцатеричном виде) 1100 0000 0000 0000 0000 0000 0000 0101 (в

двоичном виде)

Биты 30 и 31 установлены в 1, указывая, что нарушение доступа является ошиб кой (поток не может продолжить выполнение) Бит 29 равен 0, а это значит, что дан ный код определен Microsoft. Бит 28 равен 0, так как зарезервирован на будущее. Биты 16-27 равны 0, сообщая код подсистемы FACILITY_NULL (нарушение доступа может произойти в любой подсистеме операционной системы, а нс в какой-то одной). Биты 0-15 дают значение 5, которое означает лишь то, что Microsoft присвоила исключе нию, связанному с нарушением доступа, код 5.

Функция GetExceptionlnformation

Когда возникает исключение, операционная система заталкивает в стек соответству ющего потока структуры EXCEPTION_RECORD, CONTEXT и EXCEPTION_POINTERS

EXCEPTlON_RECORD содержит информацию об исключении, независимую от типа процессора, a CONTEXT — машинно-зависимую информацию об этом исключении В структуре EXCEPTIONPOINTERS всего два элемента — указатели на помещенные в стек структуры EXCEPTlON_RECORD и CONTEXT.

typedef struct _EXCEPTION_POINTERS

{

PEXCEPTION_RECORD ExceptionRecord;

PCONTEXT ConlexlRecofd;

} EXCEPTTON_POINTERS, *PEXCEPTION_POINTERS;

Чтобы получить эту информацию и использовать ее в программе, вызовите GetEx ceptionInformatton-.

PEXCEPTION_POINTERS GetExceptionInformation();

Эта встраиваемая функция возвращает' указатель на структуру EXCEPTION_POINTERS.

Самое важное в GetExceptionInformatton то, что ее можно вызывать только в филь тре исключений и больше нигде, потому что структуры CONTEXT, EXCEPTION_RE CORD и EXCEPTION_POINTERS существуют лишь во время обработки фильтра исклю чений. Когда управление переходит к обработчику исключений, эти данные в стеке разрушаются.

Если Вам нужно получить доступ к информации об исключении из обработчика, сохраните струкчуру EXCEPTION_RECORD и/или CONTEXT (на которые указывают элементы структуры EXCEPTIONPOINTERS) в объявленных Вами переменных Вот пример сохранения этих структур:

void FuncSkunk()

{

//объявляем переменные, которые мы сможем потом использовать

//для сохранения информации об исключении (если оно произойдет)

EXCEPTION_RECORD SavedExceptRec; CONTEXT SavedContext;

...

__try

{

...

}

__except

(SavedExceptRec = *(GetExceptionInformation())- >ExceptionRecord;

SavedContext = *(GetExceptionInformation())- >ContextRecord;

EXCEPTION_EXECUTE_HANDIER)

{

//мы можем теперь использовать переменные SavedExceptRec

//и SavedContext в блоке обработчика исключений

switch (SavedExceptRec ExceptionCode)

{

...

}

}

...

}

Вфильтре исключений применяется оператор-запятая (,) — мало кто из програм мистов знает о нсм. Он указывает компилятору, что выражения, отделенные запяты ми, следует выполнять слева направо После вычисления всех выражений возвраща ется результат последнего из них — крайнего справа.

ВFuncSkunk сначала вычисляется выражение слева, что приводит к сохранению находящейся в стеке структуры EXCEPTION_RECORD в локальной переменной Saved ExceptRec. Результат этого выражения является значением SavedExceptRec IIo он от брасывается, и вычисляется выражение, расположенное правее Это приводит к со хранению размещенной в стеке структуры CONTEXT в локальной переменной Saved-

Context. И снова результат — значение SavedContexl — отбрасывается, и вычисляется третье выражение. Оно равно EXCEPTION_EXECUTE_HANDLER — это и будет резуль татом всего выражения в скобках.

Так как фильтр возвращает EXCEPTION_EXECUTE_HANDLER, выполняется код в блоке except. К этому моменту переменные SavedExceptRec и SavedContext уже иници ализированы, и их можно использовать в данном блоке. Важно, чтобы переменные

SavedExceptRec и SavedContext были объявлены вне блока try

Вероятно, Вы уже догадались, что элемент ExceptionRecord структуры EXCEP TION_POINTERS указывает на структуру EXCEPTION_RECORD:

typedef struct _EXCEPTION_RECORD

{

DWORD ExceptionCode;

DWORD ExcepLionFlags;

struct _EXCEPTION_RECORD *ExceptionRecord; PVOID ExceptionAddress;

DWORD NurrberParameters;

ULONG_PTR ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];

} EXCEPTION_RECORD;

Структура EXCEPTIONRECORD содержит подробную машинно-независимую ин формацию о последнем исключении. Вот что представляют собой ec элементы.

ExceptionCode — код исключения . Это информация, возвращаемая функцией

GetExceptionCode.

ExceptionFlags — флаги исключения. На данный момент определено только два значения: 0 (возобновляемое исключение) и EXCEPTION_NONCONTINUABLE (невозобновляемое исключение). Любая попытка возобновить работу програм мы после невозобновляемого исключения генерирует исключение EXCEP

TION_NONCONTINUABLE_EXCEPTION.

ExceptionRecord - указатель на структуру EXCEPTION_RECORD, содержащую информацию о другом необработанном исключении При обработке одного исключения может возникнуть другое. Например, код внутри фильтра исклю чений может попытаться выполнить деление на нуль. Когда возникает серия вложенных исключений, записи с информацией о них могут образовывать связанный список Исключение будет вложенным, если оно генерируется при обработке фильтра. В отсутствие необработанных исключений ExceptionRecord равен NULL.

ExceptionAddress — адрес машинной команды, при выполнении которой про изошло исключение

NumberParameters — количество параметров, связанных с исключением (0-15). Это число заполненных элементов в массиве ExceptionInformation. Почти для всех исключений значение этого элемента равно 0.

ExceptionInformation — массив дополнительных аргументов, описывающих ис ключение. Почти для всех исключений элементы этого массива не определены.

Последние два элемента структуры EXCEPTION_RECORD сообщают фильтру до полнительную информацию об исключении. Сейчас такую информацию дает только один тип исключений EXCEPTION_ACCESS_VIOLATION. Все остальные дают нулевое значение в элементе NumberParameters. Проверив его, Вы узнаете, надо ли присмат ривать массив ExceptionInformation.

При исключении EXCEPTION_ACCESS_VIOLATION эелемент ExceplionInformation[0]

содержит флаг, указывающий тип операции, которая вызвала нарушение доступа. Если его значение равно 0, поток пытался читать недоступные ему данные; Т — записы вать данные по недоступному ему адресу. Элемент ExceptionInformation[l] определяет адрес недоступных данных.

Эта структура позволяет писать фильтры исключений, сообщающие значительный объем информации о работе программы. Можно создать, например, такой фильтр:

__try

{

...

}

__except (ExpFltr(GetExceptionInformation()->ExceptionRecord))

{

...

}

LONG ExpFltr(PEXCEPTION_RECORD pER)

{

char szBuf[300], *p;

DWORD dwExceptionCode = pER->ExceptionCode;

sprintf(szBuf, "Code = %x, Address = %p", dwExceptionCode, pER- >ExceptionAddress);

//находим конец строки p = strchr(szBuf, 0);

//я использовал оператор switch на тот случай, если Microsoft

//в будущем добавит информацию для других исключений

switch (dwExceptionCode)

{

case EXCEPTION_ACCESS_VIOLATION: