Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Рихтер Дж., Назар К. - Windows via C C++. Программирование на языке Visual C++ - 2009

.pdf
Скачиваний:
6503
Добавлен:
13.08.2013
Размер:
31.38 Mб
Скачать

764 Часть V. Структурная обработка исключений

Перед завершением главного потока выводится последнее сообщение об отсутствии необработанных исключений:

После того как вы закроете и это окно, процесс нормально завершится, поскольку функция _tWinMain вернет управление. Заметьте, что данное окно не появляется при аварийном завершении процесса.

А сейчас снова запустим эту программу. Но на этот раз попробуйте щелкнуть кнопку Yes, чтобы обратиться к памяти по недопустимому адресу (попытаться записать 5 по адресу NULL). В результате возникает необработанное нарушение доступа и в Windows XP открывается следующее окно.

Рис. 23-1. Сообщение о необработанном исключении в Windows XP

В Windows Vista соответствующее окно выглядит так:

Рис. 23-2. Первое сообщение о необработанном исключении в Windows Vista

Глава 23. Обработчики завершения.docx 765

Если закрыть его щелчком кнопки Cancel, приложение по-тихому завершится. В противном случае выводится окно следующего пила:

Рис. 23-3. Второе сообщение о необработанном исключении в Windows Vista

Щелчок кнопки Debug система выполняет действия, описанные в главе 25, и запускает отладчик, который подключается к сбойному процессу. Если вместо этого щелкнуть Close Program (в Windows Vista), Send Error Report либо Don't Send (в Windows XP), процесс завершится. Однако в коде программы-примера есть блок finally, поэтому он должен быть исполнен перед завершением процесса. При этом в Windows XP вывод1ггся следующее сообщение:

Блок finally исполняется, поскольку код в блоке try завершился аварийно. Если закрыть это окно, процесс действительно завершится. Однако это происходит только в версиях Windows, предшествующих Vista, в которых блок finally исполняется только в случае глобальной раскрутки. Как сказано в главе 6, точка входа потока защищена блоком try/except. В этом случае вызывается функция фильтра исключений в __except(), которая должна вернуть EXCEPTION_EXECUTE_ HANDLER. В Windows Vista механизмы необработанных исключений были в значительной степени переделаны с целью повышения надежности (см. главу 25). Сразу бросается в глаза один из недостатков этих нововведений: возвращается фильтр исключений, являющийся также его оболочкой, возвращает EXCEPTION_CONTINUE_SEARCH, поэтому процесс тут же завершается без шансов на исполнение блока finally.

Код SEHTerm.exe проверяет, в какой системе он работает. Если это Windows Vista, следующее окно позволяет указать, следует ли защитить сбойную функцию блоком try/except.

766 Часть V. Структурная обработка исключений

Если щелкнуть кнопку Yes, блок try/finally будет защищен фильтром исключений, который всегда возвращает EXCEPTION_EXECUTE_HANDLER. При этом в случае возникновения исключения непременно начинается глобальная раскрутка, и при исполнении блока finally открывается окно следующего вида:

Перед завершением главного потока приложения с кодом -1 блок except выводит следующее сообщение:

Если же щелкнуть кнопку No, при возникновении исключения приложение завершится без исполнения блока finally (если вы не выберете запуск отладки).

SEHTerm.cpp

/****************************************************************************** Module: SEHTerm.cpp

Notices: Copyright (c) 2008 Jeffrey Richter & Christophe Nasarre

******************************************************************************/

#include "..\CommonFiles\CmnHdr.h" /* See Appendix A. */ #include <windows.h>

#include <tchar.h>

///////////////////////////////////////////////////////////////////////////////

BOOL IsWindowsVista() {

//Code from Chapter 4

//Prepare the OSVERSIONINFOEX structure to indicate Windows Vista. OSVERSIONINFOEX osver = { 0 };

osver.dwOSVersionInfoSize = sizeof(osver); osver.dwMajorVersion = 6; osver.dwMinorVersion = 0; osver.dwPlatformId = VER_PLATFORM_WIN32_NT;

Глава 23. Обработчики завершения.docx 767

// Prepare the condition mask.

DWORDLONG dwlConditionMask = 0; // You MUST initialize this to 0. VER_SET_CONDITION(dwlConditionMask, VER_MAJORVERSION, VER_EQUAL); VER_SET_CONDITION(dwlConditionMask, VER_MINORVERSION, VER_EQUAL); VER_SET_CONDITION(dwlConditionMask, VER_PLATFORMID, VER_EQUAL);

// Perform the version test.

if (VerifyVersionInfo(&osver, VER_MAJORVERSION | VER_MINORVERSION | VER_PLATFORMID, dwlConditionMask)) {

//The host system is Windows Vista exactly. return(TRUE);

}else {

//The host system is NOT Windows Vista. return(FALSE);

}

}

void TriggerException() {

__try {

int n = MessageBox(NULL, TEXT("Perform invalid memory access?"), TEXT("SEHTerm: In try block"), MB_YESNO);

if (n == IDYES) {

* (PBYTE) NULL = 5; // This causes an access violation

}

}

__finally {

PCTSTR psz = AbnormalTermination()

? TEXT("Abnormal termination") : TEXT("Normal termination"); MessageBox(NULL, psz, TEXT("SEHTerm: In finally block"), MB_OK);

}

MessageBox(NULL, TEXT("Normal function termination"), TEXT("SEHTerm: After finally block"), MB_OK);

}

int WINAPI _tWinMain(HINSTANCE, HINSTANCE, PTSTR, int) {

//In Windows Vista, a global unwind occurs if an except filter

//returns EXCEPTION_EXECUTE_HANDLER. If an unhandled exception

//occurs, the process is simply terminated and the finally blocks

//are not exectuted.

if (IsWindowsVista()) {

768 Часть V. Структурная обработка исключений

DWORD n = MessageBox(NULL, TEXT("Protect with try/except?"),

TEXT("SEHTerm: workflow"), MB_YESNO);

if (n == IDYES) { __try {

TriggerException();

}

__except (EXCEPTION_EXECUTE_HANDLER) {

//But the system dialog will not appear.

//So, popup a message box.

MessageBox(NULL, TEXT("Abnormal process termination"),

TEXT("Process entry point try/except handler"), MB_OK);

// Exit with a dedicated error code return(-1);

}

} else { TriggerException();

}

} else { TriggerException();

}

MessageBox(NULL, TEXT("Normal process termination"),

TEXT("SEHTerm: before leaving the main thread"), MB_OK);

return(0);

}

//////////////////////////////// End of File //////////////////////////////////

Оглавление

 

Г Л А В А 2 4 Фильтры и обработчики исключений ..........................................................

769

Примеры использования фильтров и обработчиков исключений................................

770

Funcmeister1........................................................................................................................

770

Funcmeister2........................................................................................................................

771

EXCEPTION_EXECUTE_HANDLER.........................................................................................

773

Некоторые полезные примеры.....................................................................................

774

Глобальная раскрутка......................................................................................................

777

Остановка глобальной раскрутки ................................................................................

780

EXCEPTION_CONTINUE_EXECUTION....................................................................................

782

Будьте осторожны с EXCEPTION_CONTINUE_EXECUTION...................................

783

EXCEPTION_CONTINUE_SEARCH..........................................................................................

784

Функция GetExceptionCode.............................................................................................

786

Функция GetExceptionInformation .................................................................................

791

Программные исключения .............................................................................................

795

Г Л А В А 2 4

Фильтры и обработчики исключений

Исключение — это событие, которого вы не ожидали. В хорошо написанной программе не предполагается попыток обращения по неверному адресу или деления на нуль. И все же такие ошибки случаются. За перехват попыток обращения по неверному адресу и деления на нуль отвечает центральный процессор, возбуждающий исключения в ответ на эти ошибки. Исключение, возбужденное процессором, называется аппаратным (hardware exception). Далее мы увидим, что операционная система и прикладные программы способны возбуждать собственные исключения — программные (software exceptions).

При возникновении аппаратного или программного исключения операционная система дает вашему приложению шанс определить его тип и самостоятельно обработать. Синтаксис обработчика исключений таков:

_try {

// защищенный блок

}

__except (exception filter) { // обработчик исключений

}

Обратите внимание на ключевое слово __cxcept. За блоком try всегда должен следовать либо блок finnаllу, либо блок except. Для данного блока try нельзя указать одновременно и блок finally, и блок except; к тому же за try не может следовать несколько блоков finally или except. Однако try-finally можно вложить в tryexcept, и наоборот.

770 Часть V. Структурная обработка исключений

Примеры использования фильтров и обработчиков исключений

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

Funcmeister1

Вот более конкретный пример блока try-except:

DWORD Funcmeister1() {

DWORD dwTemp;

// 1. Что-то делаем здесь

_try {

// 2. Выполняем какую-то операцию dwTemp = 0;

}

__except (EXCEPTION_EXECUTE_HANDLER) {

// обрабатываем исключение; этот код никогда не выполняется

}

// 3. Продолжаем что-то делать return(dwTemp);

}

В блоке try функции Funcmeister1 мы просто присваиваем 0 переменной dwTemp. Такая операция не приведет к исключению, и поэтому код в блоке except никогда не выполняется. Обратите внимание на такую особенность: конструкция try-finally ведет себя иначе. После того как переменной dwTemp присваивается 0, следующим исполняемым оператором оказывается return.

Хотя ставить операторы return, goto, continue и break в блоке try обработчика завершения настоятельно не рекомендуется, их применение в этом блоке не приводит к снижению быстродействия кода или к увеличению его размера. Использование этих операторов в блоке try, связанном с блоком except, не вызовет таких неприятностей, как локальная раскрутка.

Глава 24. Фильтры и обработчики исключений.docx 771

Funcmeister2

Попробуем модифицировать нашу функцию и посмотрим, что будет:

DWORD Funcmeister2() {

DWORD dwTemp = 0;

 

// 1. Что-то делаем здесь

 

 

_try {

 

// 2. Выполняем какую-то операцию

 

dwTemp = 5 / dwTemp;

// генерирует исключение

dwTemp += 10;

// никогда не выполняется

}

__except ( /* 3. Проверяем фильтр. */ EXCEPTION_EXECUTE_HANDLER) { // 4. Обрабатываем исключение.

MessageBeep(0);

}

// 5. Продолжаем что-то делать eturn(dwTemp);

}

Инструкция внутри блока try функции Funcmeister2 пытается поделить 5 на 0. Перехватив это событие, процессор возбуждает аппаратное исключение. Тогда операционная система ищет начало блока except и проверяет выражение, указанное в качестве фильтра исключений; оно должно дать один из трех идентификаторов, определенных в заголовочном Windows-файле Excpt.h.

Табл. 24-1. Значения, возвращаемые фильтром исключений

Идентификатор

Значение

EXCEPTION_EXECUTE_HANDLER

1

EXCEPTION_CONTINUE_SEARCH

0

EXCEPTION_CONTINUE_EXECUTION

-1

Далее мы обсудим, как эти идентификаторы изменяют выполнение потока. Читая следующие разделы, посматривайте на блок-схему на рис. 24-1, которая иллюстрирует операции, выполняемые системой после генерации; исключения.

Соседние файлы в предмете Программирование на C++