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

Роббинс Д. - Отладка приложений для Microsoft .NET и Microsoft Windows - 2004

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

ГЛАВА 13 Обработчики ошибок

513

 

 

//Я должен был вынести этот блок за пределы функций

//SnapCurrentProcessMiniDumpA/W, так как они используют

//соглашение вызова naked и поэтому не могут работать с SEH. BOOL CalculateBeginningOfCallInstruction ( UINT_PTR & dwRetAddr )

{

BOOL bRet = TRUE ;

//При обработке исключений я обеспечиваю полную защиту.

//Мне нужно быть чрезвычайно внимательным, так как я читаю

//стек и могу исказить его вершину. Я не хочу, чтобы вызов

//функции SnapCurrentProcessMiniDump приводил к краху

//приложения, поэтому я обрабатываю все возможные исключения. __try

{

BYTE * pBytes = (BYTE*)dwRetAddr ;

if ( 0xE8 == *(pBytes k_CALLNEARBACK) )

{

dwRetAddr = k_CALLNEARBACK ;

}

else if ( 0xFF == *(pBytes k_CALLFARBACK) )

{

dwRetAddr = k_CALLFARBACK ;

}

else

{

bRet = FALSE ;

}

}

__except ( EXCEPTION_EXECUTE_HANDLER )

{

bRet = FALSE ;

}

return ( bRet ) ;

}

Резюме

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

Исключения C++ и исключения SEH иногда путают. Исключения C++ входят в спецификацию языка C++, в то время как исключения SEH обеспечивает ОС; эти два типа обработки исключений абсолютно разные, хотя и тесно сплетены в де талях реализации.

Надеюсь, я смог показать вам всю голую правду об обработке исключений C++, и теперь вы дважды подумаете, прежде чем решитесь использовать их в своем

514 ЧАСТЬ IV Мощные средства и методы отладки неуправляемого кода

приложении. Во первых, из за дополнительных расходов они ухудшают быстро действие программ. Однако гораздо хуже то, что в реализации компиляторов Microsoft блок catch (...) «съедает» ошибки SEH. Фактически это делает блок catch (...) самой плохой конструкцией программирования, которую только можно вообразить. Кроме того, нужно избегать функции _set_se_translator, потому что она работает не так, как многие предполагают. Возможно, некоторые пуристы объектно ориентированного программирования и языка C++ найдут мои взгля ды на исключения C++ излишне жесткими, но мне кажется, что единственная чистота, которая имеет значение, — это своевременная разработка качественных программ. Если вы откажетесь от обработки исключений C++, ваши программы станут чистыми настолько, насколько это вообще возможно.

Своим существованием обработчики ошибок обязаны магической функции SetUnhandledExceptionFilter, позволяющей установить конечный фильтр исключе ний SEH, который обеспечивает получение управления прямо перед появлением диалогового окна сообщения об ошибке и записать бесценную информацию о причинах проблемы. Приведенные мной функции API CrashHandler облегчат уста новку фильтров необработанных исключений и выполнят за вас всю грязную работу по преобразованию информации об ошибке, благодаря чему вы сможете сосредоточиться на отображении информации и уникальных компонентах свое го приложения.

В конце главы я рассказал про одну чрезвычайно полезную новую API функ цию — MiniDumpWriteDump. Она имеет несколько недостатков, но я о них позабо тился, сделав создание и последующее изучение минидампов максимально удоб ным. Вооружившись минидампами, созданными в самые подходящие моменты, вы сможете решать любые проблемы своих клиентов.

Г Л А В А

14

Отладка служб Windows и DLL, загружаемых

в службы

После драйверов устройств сложнее всего отлаживать код служб Microsoft Win dows и DLL, загружаемых в службы. Может показаться, что, раз службы являются всего лишь процессами пользовательского режима без UI, то отлаживать их столь же легко, как и консольные приложения. Увы, все не так просто. На самом деле со службами Windows и DLL, загружаемыми в службы, связано столько подводных камней, особенно касающихся защиты в Windows, что при работе с ними вам может захотеться рвать на себе волосы. При появлении Microsoft Windows NT очень немногие разработчики писали службы или вообще знали, что они существуют. Однако в сегодняшнем мире COM+, Microsoft Internet Information Services (IIS), расширений Microsoft Exchange Server и Windows Clustering многим разработчи кам придется иметь дело со службами. И отлаживать их.

В этой главе я представлю обзор основных характеристик служб. Чтобы по нять, как отлаживать службы и DLL, загружаемые в службы, такие как ISAPI филь тры и расширения, надо знать, как службы работают. Затем я поясню аспекты, напрямую связанные с отладкой служб. По мере прохождения этапов отладки службы я буду отмечать моменты, касающиеся определенных технологий служб Microsoft.

Основы служб

Служба характеризуется тремя основными свойствами:

служба должна работать постоянно, даже если в системе компьютера никто не зарегистрирован или при первоначальном запуске компьютера;

516 ЧАСТЬ IV Мощные средства и методы отладки неуправляемого кода

служба не имеет UI;

службу могут контролировать и управлять ею как локальные, так и удаленные клиенты.

Решая, как реализовать свое приложение: в виде службы или обычного прило жения пользовательского режима, — спросите себя, предъявляются ли к пробле ме, которую вы хотите решить, эти три требования. Если да, надо реализовать приложение как службу. А если вы решили написать службу (и хотите ее отлажи вать), убедитесь, что вы четко понимаете работу служб. Сведений, приведенных в этом разделе, хватит, чтобы составить представление о том, с чем вам придется столкнуться. Если хотите узнать о службах больше, ознакомьтесь с прекрасной книгой Джеффри Рихтера (Jeffrey Richter) и Джейсона Кларка (Jason Clark) «Prog ramming Server Side Applications for Microsoft Windows 2000» (Microsoft Press, 2000 г.)1.

Прекрасный пример случая, когда следует писать службу, — создание прило жения, контролирующего источник бесперебойного питания (UPS). Все, что нужно делать ПО для UPS, — следить, когда UPS сообщит о сбое питания в сети, а когда заряд батареи подойдет к концу, программе следует инициировать управляемое выключение (controlled shutdown). Очевидно, что если ПО для UPS не работает постоянно (первый критерий в решении, должно ли приложение быть службой), выключения не произойдет, и, когда в UPS закончится заряд батарей, компьютер просто остановится. В ПО для UPS нет необходимости в UI (второй критерий), так как ему лишь надо выполняться в фоновом режиме, следя за UPS. Наконец, если вы работаете над системой бесперебойного питания для хранилищ данных, сис темные администраторы определенно захотят проверять состояние удаленных UPS (третий критерий).

Пока все довольно просто. Теперь приступим к работе служб. Первый аспект, о котором я расскажу, — специальные функции API, вызываемые для превраще ния обычного процесса пользовательского режима в службу.

API

Некоторые качества служб потребуют от вас определенных действий, чтобы при способиться к ним. Во первых, не важно, какую точку входа вы используете в служ бах: main или WinMain. Поскольку службы не имеют UI, точки входа для консоль ных приложений или приложений с GUI взаимозаменяемы.

Внутри main или WinMain прежде всего следует вызвать функцию API StartService CtrlDispatcher. Ей передается структура SERVICE_TABLE_ENTRY, в которой указывает ся имя и главная точка входа службы. Диспетчер управления службами (Service Control Manager, SCM), запускающий все службы, с которым в конечном счете общается StartServiceCtrlDispatcher, чтобы установить вашу службу, является сред ством ОС, которое, как следует из его названия, управляет всеми службами. Если ваша служба не вызовет StartServiceCtrlDispatcher в течение 30 секунд с момента запуска, SCM завершит ее работу. Как вы увидите ниже, такое ограничение по времени может сделать запуск отладки чуть интереснее.

1Рихтер Дж., Кларк Дж. Программирование серверных приложений для Microsoft Windows 2000. — М.: «Русская Редакция», 2001. — Прим. перев.

ГЛАВА 14 Отладка служб Windows и DLL, загружаемых в службы

517

 

 

Когда вы вызываете SCM, он создает поток для вызова точки входа вашей службы. К точке входа службы предъявляется одно жесткое требование: нужно зарегист рировать обработчик через RegisterServiceCtrlHandlerEx и вызвать SetServiceStatus

втечение 82 секунд с момента запуска. Если за это время служба не выполняет вызовов, SCM считает, что в службе произошел сбой, хотя и не завершает ее. Если

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

RegisterServiceCtrlHandlerEx принимает еще другой указатель — на функцию обработчик. SCM вызывает функцию обработчик для управления рабочими харак теристиками службы в таких операциях, как остановка, приостановка или возоб новление.

Когда служба переходит между состояниями, запускаясь, останавливаясь и приостанавливаясь, она общается с SCM через функцию API SetServiceStatus. Боль шинству служб надо просто вызвать SetServiceStatus и инициировать основное состояние, в которое они переходят, — в этой функции нет ничего особенного.

Ясгладил некоторые подробности, связанные с функциями API, но обычно

вызовы StartServiceCtrlDispatcher, RegisterServiceCtrlHandlerEx и SetServiceStatus

все, что нужно ОС от вашей службы, чтобы обеспечить ее работоспособность. За метьте, я ничего не упомянул о требованиях к коммуникационным протоколам, используемым службой для связи между написанным вами UI контроллера и ва шей службой. К счастью, службы имеют доступ ко всем обычным функциям Win dows API, так что вы вправе использовать проецируемые в память файлы (memory mapped files), почтовые ящики (mail slots), именованные каналы (named pipes) и т. д. В службах вам действительно доступны те же варианты, что и в обычном меж процессном взаимодействии. Самая сложная проблема со службами, как я гово рил в начале главы, — это защита.

Защита

Если не указать иное, службы выполняются под специальной учетной записью System. Поскольку Windows для всех объектов реализует защиту на уровне пользо вателей, учетная запись System допустима для машины, а не для сети в целом. Следовательно, процесс под учетной записью System не имеет доступа к сетевым ресурсам. Для многих служб, скажем, для упомянутого выше примера с UPS, про блем защиты в процессе разработки может не возникнуть. Но, если вы, например, пытаетесь разделить проецируемую память от службы к клиентскому приложению с UI, а защита установлена неправильно, вы столкнетесь с ошибками нарушения прав доступа от клиентских приложений, когда они будут пытаться проецировать общую память.

К сожалению, отладкой проблем защиты не решить — вам придется обеспе чить программирование служб и клиентских приложений с правильно настроенной защитой. Полное описание программирования защиты в Windows займет отдель ную книгу, так что приготовьтесь провести некоторое время, планируя програм мирование защиты с самого начала разработки. Чтобы у вас сложилось представ ление о диапазоне нюансов с защитой в службах, настоятельно рекомендую ста

518 ЧАСТЬ IV Мощные средства и методы отладки неуправляемого кода

тью Фрэнка Кима (Frank Kim) «Why Do Certain Win32 Technologies Misbehave in Windows NT Services?» в мартовском номере «Microsoft Systems Journal» за 1998 год. Есть и другие прекрасные ресурсы: рубрика Кейта Брауна (Keith Brown) «Security Briefs» в «Microsoft Systems Journal» и его книга «Programming Windows Security» (Addison Wesley, 2000). Наконец, одна из лучших книг о реальном мире защиты Windows — «Writing Secure Code, Second Edition» Майкла Говарда (Michael Howard) и Дэвида Лебланка (David LeBlanc) (Microsoft Press, 2003)2.

Теперь, пронесшись вихрем по службам, обратимся к сердцу этой главы — от ладке служб.

Отладка служб

Как вы видели, уже одна уникальная природа служб означает, что вам придется сталкиваться с вопросами, не возникающими при разборке обычных приложений пользовательского режима. Учтите, что до сих пор речь шла лишь о минималь ной функциональности, необходимой для службы. Я даже не касался фундамен тальных требований обеспечения работы общих алгоритмов и реализаций с осо быми элементами службы. Простейший и лучший способ отладки служб без рис ка быть раздавленным — подойти к отладке поэтапно.

В отладке служб два основных этапа:

отладка базового кода;

отладка службы.

Отладка базового кода

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

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

Службы COM+

Если вы собираете службу COM+ с помощью Active Template Library (ATL), вам ничего не нужно делать с безопасностью. По умолчанию ATL запускается как исполняе мый файл пользовательского режима пока вы не зарегистрируете свое приложе ние с параметром командной строки Service.

2 Говард M., Лебланк Д. Защищенный код. — М.: Русская Редакция, 2003. — Прим. перев.

ГЛАВА 14 Отладка служб Windows и DLL, загружаемых в службы

519

 

 

ISAPI-фильтры и расширения

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

Exchange Server

Можно собирать службы Exchange Server, запускающиеся в виде консольных при ложений, используя вспомогательные функции из WINWRAP.LIB. Запуск службы со стартовым параметром notserv вызовет ее исполнение в виде обычного про цесса; notserv должен быть первым среди указанных параметров.

Отладка службы

После тестирования и отладки общей логики можете приступать к отладке ваше го кода, выполняющегося как служба. Вся первоначальная отладка должна прохо дить в системе, где все под вашим контролем. В идеале нужна вторая машина ря дом с главной машиной для разработки, которую можно использовать для перво начальной отладки. На второй машине должна быть та же по версии и особенно стям система Windows, что рекомендуется пользователям для среды, в которой будет работать ваша служба. Цель отладки базового кода — проверка основной логики, тогда как предварительная отладка службы выполняется, чтобы «перетряхнуть» основной код, относящийся к службе. В ходе отладки вашего первого кода служ бы следует выполнить четыре задачи:

включить Allow Service To Interact With Desktop;

установить идентификационные данные службы;

подключиться к службе;

отладить стартовый код.

Включение Allow Service To Interact With Desktop

Независимо от типа отлаживаемой службы следует включить Allow Service To Interact With Desktop (Разрешить взаимодействие с рабочим столом) на вкладке Log On (Вход в систему) диалогового окна Properties (Свойства) службы. Хотя в службе не должно быть элементов UI, уведомления утверждений (assertion notifications), которые позволяют получить управление в отладчике, очень помогут. Уведомле ния утверждений в сочетании с прекрасным регистрирующим кодом (logging code), таким, какой предоставляет вам ATL для записи в журнал событий, могут облег чить отладку служб.

На начальных стадиях отладки я включаю диалог утверждений SUPERASSERT, чтобы быстро оценить общее состояние моего кода. (О SUPERASSERT см. главу 3.) Но по мере выполнения службы я устанавливаю параметры утверждений так, чтобы все утверждения проходили только через операторы трассировки.

Пока я не уверюсь в коде службы, я обычно оставляю параметр Allow Service To Interact With Desktop включенным. Одну мерзкую ошибку, встретившуюся в написанной мною как то службе, я долго не мог обнаружить, поскольку я отклю

520 ЧАСТЬ IV Мощные средства и методы отладки неуправляемого кода

чил его при выведенном информационном окне. Поскольку защита ОС не позво ляет обычным службам выводить информационные окна, моя служба просто за висала. До того как отключить Allow Service To Interact With Desktop, я дважды удостоверяюсь, что моя служба (и все используемые ею DLL) не вызывает инфор мационные окна, проверяя с помощью DUMPBIN/IMPORTS, что ни MessageBoxA, ни MessageBoxW не импортируются там, где я этого не жду.

Если для своих утверждений вы используете SUPERASSERT, вам повезло. Даже когда вы забываете отключить его диалоговые уведомления, прежде чем отобразить замечательное диалоговое окно с уведомлением, SUPERASSERT проверяет, что про цесс выполняется с видимым рабочим столом. Вообще эта особенность столь полезна, что я инкапсулировал ее в функции BSUIsInteractiveUser (BSUFUNCTI ONS.CPP) из BugslayerUtil.DLL.

Установка идентификационных данных службы

Чтобы избежать проблем с защитой при попытках заставить службу работать, можно установить идентификационные данные службы. По умолчанию все службы выполняются под учетной записью System, которая иногда называется учетной за писью LocalSystem. Однако вы вправе настроить службу на работу под учетной записью пользователя с более высоким уровнем доступа, скажем, члена группы с расширенными правами.

В диалоговом окне Properties вашей службы щелкните вкладку Log On. Устано вите переключатель This Account (С учетной записью), щелкните кнопку Browse (Обзор) и выберите нужную учетную запись из диалогового окна Select User (Вы бор: Пользователь). Выбрав пользователя, введите и подтвердите пароль для этой учетной записи. Для исполняемых служб COM+ установить идентификационные данные для регистрации позволяет также DCOMCNFG.EXE.

Подключение к службе

После запуска службы отладка обычно не так сложна. Все, что надо сделать, — подключиться к процессу службы из отладчика Microsoft Visual Studio .NET. В за висимости от службы и сложности кода подключение к службе из отладчика мо жет оказаться единственным, что нужно сделать для отладки. Чтобы подключить ся к активному процессу из отладчика Visual Studio .NET, сделайте так.

1.Запустите DEVENV.EXE.

2.Выбрав Debug Processes из меню Tools, откройте диалоговое окно Processes.

3.Установите флажок Show System Processes и щелкните кнопку Refresh, чтобы увидеть все процессы службы. Выберите из списка процессы, которые нужно отладить, и щелкните кнопку Attach. Если при щелчке кнопки Attach нажать любую клавишу Ctrl, вы автоматически начнете отладку неуправляемого кода, пропустив диалог Attach To Process.

4.Если появился диалог Attach To Process, убедитесь, что установлен вариант Native и щелкните OK.

Прекрасная новинка отладчика Visual Studio .NET: теперь вы можете не повто рять все предыдущие действия каждый раз, когда надо подключиться к службе, потому что вы можете создать проект, выполняющий подключение к службе, ког

ГЛАВА 14 Отладка служб Windows и DLL, загружаемых в службы

521

 

 

да вы приступаете к отладке. Давайте создадим специальные проекты подключе ния (обратите внимание: следующие действия предполагают, что вы запускаете отладчик под учетной записью, имеющей все привилегии администратора и на ходящейся на машине в группе Debugger Users).

1.Соберите приложение. По завершении сборки закройте существующее реше ние.

2.Из меню File выберите Open Solution.

3.В диалоговом окне Open Solution измените значение в раскрывающемся списке Files Of Type на Executable Files и перейдите туда, где находится собранный EXE файл службы. Выберите EXE файл как решение и щелкните кнопку Open.

4.Сохраните решение, выбрав Save All из меню File, и в диалоговом окне Save File As присвойте ему имя вроде <проект>_Attach.SLN.

5.Щелкните правой кнопкой узел .EXE в окне Solution Explorer и из контекстно го меню выберите команду Properties.

6.На странице Debugging диалогового окна Property Pages проекта установите поле Attach на Yes (рис. 14 1).

Рис. 14 1. Страница свойств Attach Debugging

7.Щелкните OK в диалоговом окне Property Pages проекта.

8.Установите и запустите вашу службу обычным способом.

9.Когда будете готовы отлаживать службу, просто нажмите F5 в Visual Studio .NET с загруженным проектом подключения — и все!

В качестве альтернативного метода подключения отладчика можно вызвать функцию API DebugBreak. Когда появится диалоговое окно Application Error, про сто щелкните кнопку Cancel (Windows 2000) или Debug (Microsoft Windows XP/ Server 2003) и отлаживайте, как обычно. Помните: если вы собираете службу COM+, вызов DebugBreak следует выполнять за пределами любых COM методов или ини циаций свойств. Иначе COM поглотит исключение точки прерывания, генериру емое DebugBreak, и отладчик не будет подключен. Кроме того, не вызывайте Debug Break как часть начального стартового кода службы — причины я объясню в раз деле «Отладка стартового кода».

522 ЧАСТЬ IV Мощные средства и методы отладки неуправляемого кода

Другой способ подключения отладчика к вашей службе — если вы зарегист рированы в системе с правами администратора — использовать Task Manager. Вызовите Task Manager, выберите вкладку Processes, щелкните правой кнопкой процесс, который хотите отладить, и из контекстного меню выберите команду Debug. ОС позволяет легко подключить отладчик, если вам известно, какой про цесс надо отладить.

Подключать отладчик к службам могут только пользователи с правами адми нистратора на локальной машине, иначе при попытке отладить процесс, выпол няющийся не под вашей учетной записью, команда Debug выведет информаци онное окно Unable To Attach Debugger (невозможно подключить отладчик).

ISAPI-фильтры и расширения IIS

До IIS 5 все ISAPI фильтры выполнялись внутри INETINFO.EXE — главной IIS службы, т. е. вы просто подключались к INETINFO.EXE и отлаживали единый процесс. В IIS 5 и выше из за новой объединенной внепроцессной модели расширения выполня ются в DLLHOST.EXE. ISAPI фильтры по прежнему выполняются внутри IIS процесса INETINFO.EXE. Новая модель делает IIS гораздо стабильнее и, по утверждению Microsoft, гораздо более масштабируемыми. Единственная проблема с отладкой в том, что вы можете не знать, в каком процессе DLLHOST.EXE выполняется ваше расширение.

В документации IIS сказано, что следует настроить свои расширения на выпол нение внутри IIS, чтобы иметь возможность их отлаживать. Единственная проблема изменения места выполнения ваших расширений в том, что развертывать их надо, используя объединенную внепроцессную модель. Поскольку я проповедую отладку в сценариях, близких к тем, в которых будут работать ваши пользователи, я пока жу вам трюк, который позволит отлаживать расширения, даже когда они выпол няются в DLLHOST.EXE, т. е. там, где они будут работать.

Но, прежде чем поговорить об отладчике, надо знать, как определить, в каком процессе выполняется ваш фильтр или расширение, так как выполняются несколько экземпляров DLLHOST.EXE. Во первых, скачайте фантастическую бесплатную ути литу Process Explorer с Web сайта Марка Руссиновича (Mark Russinovich) и Брюса Когсвелла (Bruce Cogswell) www.sysinternals.com. Я впервые упомянул Process Explo rer в главе 2, потому что это прекрасный инструмент, которым можно определить, перемещались ли DLL, загруженные в ваше адресное пространство.

Process Explorer покажет вам описатели, открытые процессом, и — главное — какие DLL в какие процессы загружены. Чтобы найти вашу DLL с помощью Process Explorer, сначала нажмите Ctrl+D чтобы указать, что вы хотите просмотреть DLL, затем нажмите Ctrl+F и в диалоговом окне Process Explorer Search укажите имя файла вашей DLL в поле ввода DLL Substring. Щелкните кнопку Search, и Process Explorer покажет список имен и идентификаторов процессов (PID), в которые загружена ваша DLL. Имея PID, вы можете подключить отладчик Visual Studio .NET к процес су командой Debug Process из меню Tools. Не забудьте прочитать врезку о других возможностях Process Explorer, так как это один из лучших инструментов кото рые можно держать на жестком диске.

Если вы ищете инструмент, эквивалентный Process Explorer, но работающий из командной строки, это TLIST.EXE, поставляемый в комплекте Debugging Tools

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