Отладка приложений

       

API-функция SetUnhandledExceptionFilter


В программах на C++ имеется возможность обрабатывать аварии, защищая секции кода, в которых, по вашему мнению, может произойти тяжелый аварийный останов. Однако, как известно, аварии обыкновенно никогда не происходят там, где мы их ожидаем. К сожалению, когда пользователи узнают об аварии в своей программе, они видят только диалоговое окно Application Error и затем, возможно, программа Dr. Watson передает им немного дополнительной информации для разрешения возникшей проблемы. Как я уже говорил, можно разработать свои собственные диалоговые окна, чтобы получать информацию, которая действительно нужна вам для объяснения аварии. Этого можно добиться, устанавливая с помощью API-функции SetUnhandledExceptionFilter специальные типы обработчиков, называемых фильтрами необрабатываемых исключений. Мы уже ссылались на них как на обработчики аварий. Удивительно, что эти функциональные возможности были реализованы в Win32 начиная еще с Microsoft Windows NT 3.5, но они почти не документированы. В июльском (1999) выпуске MSDN эта функция была упомянута только в девяти темах.

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

Само собой разумеется, что я нахожу функцию SetUnhandledExceptionFilter довольно мощным инструментом. Просто взглянув на название функции (SetUnhandledExceptionFilter), можно, вероятно, догадаться, что она делает. Один ее параметр — указатель на функцию, которая вызывается в заключительном _except-блоке приложения. Эта функция возвращает те же значения, что и любой другой фильтр исключений: EXCEPTION_EXECUTE_HANDLER, EXCEPTION_CONTINUE_EXECUTION или EXCEPTION_CONTINUE_SEARCH.
В этой фильтр- функции можно выполнять любую обработку исключений, но, как говорилось выше при обсуждении С++-функции _set_se_transiator, нужно соблюдать осторожность, исключая возможность переполнения стеков. Чтобы обезопасить себя, следует избегать вызовов любых библиотек времени выполнения, а также MFC. Если вы пишете собственную функцию фильтра исключений на языке Visual Basic, то проявляйте сверхосторожность во всем, что касается доступа из исполнительной библиотеки Visual Basic. Я обязан предупредить об этих неприятностях, но могу вас уверить, что подавляющее большинство аварий происходит из-за нарушения доступа и не должно быть каких-либо проблем, если вы включите полную систему обработки аварий в свою фильтр-функцию (при условии, что сначала вы будете проверять причину исключения и, кроме того, предпримете меры, чтобы избегать вызовов функций при переполнении стека).

Фильтр исключений тоже получает указатель на структуру EXCEPTION_POINTERS. В листинге 9-5 представлено несколько подпрограмм, которые транслируют эту структуру. Поскольку каждая компания имеет различные потребности в обработчиках аварий, читателю представляется возможность написать собственный аварийный обработчик.

Следует иметь в виду две проблемы, возникающие при использовании setunhandiedExceptionFiiter. Первая: нельзя применять стандартные отладчики пользовательского режима для отладки любого фильтра необрабатываемых исключений, который вы устанавливаете. Это — известная ошибка. В статье Q173652 в Knowledge Base говорится, что под отладчиком фильтр необрабатываемых исключений не вызывается. Эта ошибка может быть немного болезненной, но в программе на C++ для отладки своего фильтра необрабатываемых исключений можно использовать следующий обходной путь: нужно вызывать его из штатного SEH-фильтра исключений. Соответствующий пример можно найти в функции Baz программы CHJTESTS.CPP, которая является частью исходного кода, поставляемого с этой книгой.

Другая проблема заключается в следующем: обработчик аварий, который указывается при вызове функции SetunhandiedExceptionFiiter, является глобальным по отношению к вашему процессу.Если вы создаете популярнейший в мире обработчик для аварий на ActiveX-элементах управления и контейнерах, то он будет выполняться даже в том случае, если аварии данного типа будут происходить не в вашей программе. Пусть это затруднение не заставит вас отказаться от применения функции SetunhandiedExceptionFiiter; у меня есть код, который должен помочь вам.



Содержание раздела