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

Еe можно вызвать только из блока finаllу; она возвращает булево значение, кото рое сообщает, был ли преждевременный выход из блока try, связанного с данным блоком finаllу. Иначе говоря, если управление естественным образом передано из try в ftnally, AbnormalTermination возвращает FALSE. А ссли выход был преждевременным — обычно либо из-за локальной раскрутки, вызванной оператором goto, return, break или continue, либо из-за глобальной раскрутки, вызванной нарушением доступа к памя ти, — то вызов AbnormalTermination дает TRUE Но, когда она возвращяет TRUE, разли чить, вызвано выполнение блока finаllу глобальной или локалыюй раскруткой, нельзя. Впрочем, это не проблема, так как Вы должны избегать кода, приводящего к локаль ной раскрутке

Funcfurter2

Следующий фрагмент демонстрирует использование встраиваемой функции Abnor malTermination:

DWORD Funcfurter2()

{

DWORD dwTemp;

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

...

1 Встраиваемая функция (intrinsic function) — особая функция, распознаваемая компилято ром Вместо генерации вызова такой функции он подставляет в точке вызова ее код. При мером встраиваемой функции является memcpy (если указан ключ компилятора /Oi). Встре чая вызов memcpy, компилятор подставляет ec код непосредственно в вызывающую функ цию Обычно это ускоряет работу программы ценой увеличения ее размера Функция AbnormalTermination отличается от тетсру тем, что существует только во встраиваемом варианте. Ее нет ни в одной библиотеке С.

__try {

//2. Запрашиваем разрешение на доступ

//к защищенным данным, а затем используем их

WaitForSingleObject(g_hSem, INFINITE);

dwTemp = Funcinator(g_dwProtectedData);

}

__finally

{

// 3. Даем и другим попользоваться защищенными данными

ReleaseSemaphore(g_hSem, 1, NULL);

if (!AbnormalTermination())

{

//в блоке try не было ошибок - управление

//передано в блок finally естественным образом

...

}

else

{

//что-то вызвало исключение, и, так как в блоке try

//нет кода, который мог бы вызвать преждевременный

//выход, блок finally выполняется из-за глобальной

//раскрутки

//если бы в блоке try был оператор goto, мы бы

//не узнали, как попали сюда

}

}

// 4. Продолжаем что-то делать

return(dwТemp);

}

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

Упрощается обработка ошибок — очистка гарантируется и проводится в од ном месте.

Улучшается восприятие текста программ. Облегчается сопровождение кода.

Удается добиться минимальных издержек по скорости и размеру кода — при условии правильного применения обработчиков.

Программа-пример SEHTerm

Эта программа, «23 SEHTerm.exe» (см. листинг на рис. 23-1), демонстрирует обработ чики завершения. Файлы исходного кода и ресурсов этой программы находятся в каталоге 23SEHTerm на компакт-диске, прилагаемом к книге.

После запуска SEHTerm ее первичный поток входит в блок try. Из него открывает ся следующее окно.

В этом окне предлагается обратиться к памяти по недопустимому адресу. (Боль шинство приложений не столь тактично — они обращаются по недопустимым адре сам, никого не

спрашивая.) Давайте обсудим, что случится, если Вы щелкнете кнопку Yes. B этом случае поток попытается записать значение 5 по нулевому адресу памяти. Запись по нулевому адресу всегда вызывает исключение, связанное с нарушением доступа. А когда поток возбуждает такое исключение, Windows 98 выводит окно, по казанное ниже.

В Windows 2000 аналогичное окно выглядит иначе

Если Вы теперь щелкнитe кнопку Сlоsе (в Windows 98) или OK (в Windows 2000), процесс завершится. Однако в исходном коде этой программы присутствует блок finally, который будет выполнен до того, как процесс завершится Из этого блока от крывается следующее окно.

Блок finаllу выполняется потому, что происходит ненормальный выход из связан ного с пим блока try. После закрытия этого окна процесс завершается.

О'кэй, а сейчас снова запустим эту программу. Но на этот раз попробуйте щелк нуть кнопку No, чтобы избежать обращения к памяти по недопустимому адресу. Тог да поток естественным образом перейдет из блока try в блок finаllу, откуда будет от крыто следующее окно.

Обратите внимание, что на этот раз в окне сообщается о нормальном выходе из блока try Когда Вы закроете это окно, поток выйдет из блока finаllу и покажет после днее окно.