Вход/Регистрация
Системное программирование в среде Windows
вернуться

Харт Джонсон М.

Шрифт:

Функция ReportException представлена в программе 4.1. Необходимые определения и заголовочные файлы не указаны, поскольку эта функция находится в том же модуле исходного кода, что и функция ReportError. 

Программа 4.1. ReportException: функция вывода сообщений об исключениях 

/* Расширение функции ReportError для генерации формируемого приложением кода исключения вместо прекращения выполнения процесса. */

VOID ReportException(LPCTSTR UserMessage, DWORD ExceptionCode)

/* Вывести сообщение о некритической ошибке. */

{

 ReportError(UserMessage, 0, TRUE);

 /* Если ошибка критическая, сгенерировать исключение. */

 if (ExceptionCode != 0) RaiseException((0x0FFFFFFF & ExceptionCode) | 0xE0000000, 0, 0, NULL);

 return;

}

Функция ReportException используется в нескольких последующих примерах. 

Модель сигналов, используемая в UNIX, значительно отличается от SEH. Сигналы могут быть пропущены или игнорированы, и логика их работы иная. Тем не менее, у этих моделей имеются и общие черты.

Значительная часть поддержки обработки сигналов в UNIX обеспечивается библиотекой С, ограниченная версия которой доступна также под управлением Windows. Во многих случаях в программах Windows вместо сигналов можно воспользоваться обработчиками управляющих сигналов консоли, описанными в конце данной главы.

Некоторые сигналы соответствуют исключениямWindows.

Перечень в некоторой мере ограниченных соответствий "сигнал-исключение" представлен ниже:

• SIGILL — EXCEPTION_PRIV_INSTRUCTION

• SIGSEGV — EXCEPTION_ACCESS_VIOLATION

• SIGFPE — семь различных исключений, связанных с выполнением операций над числами с плавающей точкой, например EXCEPTION_FLT_DIVIDE_BY_ZERO

• SIGUSR1 и SIGUSR2 — исключения, определяемые приложением

Функции RaiseException соответствует функция библиотеки С raise.

В Windows сигналы SIGILL, SIGSEGV и SIGFPE не генерируются, хотя функция raise может генерировать один из них. Сигнал SIGINT в Windows не поддерживается.

Функция UNIX kill (kill не входит в состав стандартной библиотеки С), которая посылает сигнал другому процессу, может быть сопоставлена функции Windows GenerateConsoleCtrlEvent (глава 6). Для ограниченного варианта SIGKILL в Windows имеются аналоги в виде функций TerminateProcess и TerminateThread, с помощью которых один процесс (или поток) может уничтожить другой, хотя при использовании этих функций необходимо соблюдать осторожность (см. главы 6 и 7).

Обработчики завершения

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

Обработчик завершения строится с использования ключевого слова __finally в операторе try…finally. Структура этого оператора аналогична структуре оператора try…finally, но в ней отсутствует выражение фильтра. Как и обработчики исключений, обработчики завершения предоставляют удобные возможности для закрытия дескрипторов, освобождения ресурсов, восстановления масок и выполнения иных действий, направленных на восстановление известного состояния системы после выхода из блока. Например, программа может выполнять операторы return внутри блока, оставляя всю работу по "уборке мусора" обработчику завершения. Благодаря этому отпадает необходимость во включении кода очистки в код самого блока или переходе к коду очистки при помощи оператора goto.

__try {

 /* Блок кода. */

} _finally {

 /* Обработчик завершения (блок finally). */

}

Выход из try-блока

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

• Достижение конца try-блока и "проваливание" в обработчик завершения.

• Выполнение одного из следующих операторов таким образом, что происходит выход за пределы блока:

return

break

goto [19]

longjmp
 

continue

__leave [20]

• Исключение.

Аварийное завершение

Любое завершение выполнения программы по причинам, отличным от достижения конца try-блока и "проваливания вниз" или выполнения оператора __leave, считается аварийным завершением. Результатом выполнения оператора __leave является переход в конец блока __try и передача управления вниз по тексту программы, что намного эффективнее простого использования оператора goto, поскольку не требует разворачивания стека. Для определения того, каким образом завершилось выполнение try-блока, в обработчике завершения используется следующая функция: 

19

Возможно, это дело вкуса, — то ли индивидуального, то ли корпоративного, — но многие программисты никогда не пользуются оператором goto и избегают употребления оператора break, кроме случаев его совместного использования с операторами switch и иногда — в циклах, а также совместного использования с операторами continue. Те, кто мыслит трезво, не спешат определять свою позицию в этом отношении. Обработчики завершения и исключений могут решать многие из тех задач, для решения которых вам хотелось бы привлечь оператор goto и операторы, снабженные метками.

20

Этот оператор является специфическим для компилятора Microsoft С и предоставляет эффективный способ выхода из блока try…finally без аварийного завершения выполнения.

BOOL AbnormalTermination(VOID)
 

При аварийном завершении выполнения блока эта функция возвращает значение TRUE, при нормальном — FALSE.

Примечание

Завершение будет считаться аварийным, даже если, например, последним оператором try-блока был оператор return.

Выполнение обработчика завершения и выход из него

Обработчик завершения, или блок __finally, выполняется в контексте блока или функции, работу которых он отслеживает. Управление может переходить от оператора завершения к следующему оператору. Существует и другая возможность, когда обработчик завершения выполняет оператор передачи управления (return, break, continue, goto, longjmp или __leave). Еще одной возможностью является выход из обработчика по причине возникновения исключения.

Сочетание блоков finally и except

Один try-блок может иметь только один блок finally или только один блок except, но не может иметь оба указанных блока одновременно. Поэтому нижеприведенный код вызовет появление ошибок на стадии компиляции. 

__try {

 /* Блок контролируемого кода. */

} __except (filter_expression) {

 /* Блок обработчика исключений. */

} __finally {

 /* Так делать нельзя! Это приведет к ошибке на стадии компиляции. */

}

Вместе с тем, допускается вложение одного блока в другой, что используется довольно часто. Нижеприведенный код является вполне работоспособным и обеспечивает гарантированное удаление временных файлов при выходе из цикла под управлением программы или в результате возникновения исключения. Эта методика оказывается удобной и в тех случаях, когда требуется обеспечить гарантированную отмену блокирования файлов, что будет использовано в программе 4.2. Кроме того, в коде имеется внутренний блок try…except, размещенный в том месте программы, где выполняются вычисления, в которых участвуют вещественные числа.

  • Читать дальше
  • 1
  • ...
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • ...

Ебукер (ebooker) – онлайн-библиотека на русском языке. Книги доступны онлайн, без утомительной регистрации. Огромный выбор и удобный дизайн, позволяющий читать без проблем. Добавляйте сайт в закладки! Все произведения загружаются пользователями: если считаете, что ваши авторские права нарушены – используйте форму обратной связи.

Полезные ссылки

  • Моя полка

Контакты

  • chitat.ebooker@gmail.com

Подпишитесь на рассылку: