Отладка DLL

Автор: Александр Шаргин
Источник: RSDN Magazine #0
Опубликовано: 27.01.2002
Версия текста: 1.0
Общие принципы отладки DLL
Отладка расширений оболочки Windows
Закрытие оболочки Windows
Повторный запуск оболочки
Отладка расширений в Windows NT/2000
Выгрузка DLL
Отладка Add-in'ов к Visual C++
Отладка ISAPI-расширений
Подготовка к отладке
Отладка расширения в режиме in-process
Запуск IIS в режиме обыкновенного приложения
Отладка расширения в режиме out-of-process

Общие принципы отладки DLL

Хотя в виде DLL реализуются самые различные объекты, существует 2 общих принципа отладки, применимых ко всем разновидностям DLL.

Дальнейшая отладка DLL ничем принципиально не отличается от отладки приложений.

Иногда приложение, использующее DLL, само должно запускаться ещё одним приложением (именно такая ситуация имеет место с ISAPI-расширениями, которые загружает сервис IIS). В этом случае можно придерживаться следующей тактики.

  1. Подключиться к приложению, используя методики из предыдущего раздела (в данном случае вызов DebugBreak придётся вставлять в код DLL). Если приложение продолжает выполнение, остановить его (Debug->Break).
  2. Убедиться, что отладчик загрузил символы для DLL (в окне Debug должна появиться строчка вида "Loaded symbols for <имя DLL>"). Если этого не произошло, следует добавить отлаживаемую DLL в список Additional DLLs.
  3. Открыть файлы с исходными текстами DLL (не открывая её проекта!) и расставить необходимые точки останова.
  4. Возобновить выполнение приложения.

Отладка расширений оболочки Windows

Для расширений оболочки Windows в качестве отлаживаемого приложения указывается explorer.exe.

Закрытие оболочки Windows

Поскольку в системе не могут работать две оболочки одновременно (об исключениях из этого правила мы поговорим немного позже), необходимо завершить оболочку Windows, прежде чем запускать новую из-под отладчика. Чтобы завершить оболочку, нужно:

ПРИМЕЧАНИЕ

В Windows 2000 вместо кнопки No следует щёлкнуть по кнопке Cancel.

Повторный запуск оболочки

Чтобы снова запустить оболочку по окончании сеанса отладки, достаточно запустить explorer.exe из любой оболочки или из командной строки. Если ни оболочки, ни командной строки под рукой нет, можно использовать следующие приёмы.

Под Windows NT/2000:

Под Windows 9x:

Отладка расширений в Windows NT/2000

В Windows NT/2000 можно запускать каждый новый экземпляр Проводника (Windows Explorer) в отдельном процессе (по умолчанию рабочий стол, панель задач и все Проводники запускаются в отдельных потоках одного процесса Explorer.exe). Благодаря этому можно обойтись без постоянных перезапусков оболочки. Чтобы включить этот режим работы оболочки, необходимо открыть в редакторе реестра ключ HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer, добавить в него параметр DesktopProcess (типа REG_DWORD) и назначить ему значение "1". Изменения вступят в силу после выхода и повторного входа в систему.

Выгрузка DLL

В обычном режиме работы оболочка выгружает DLL не сразу, а по истечении некоторого промежутка времени. Это может помешать линкеру перезаписывать файл DLL. Чтобы оболочка выгружала DLL немедленно, нужно создать в реестре ключ HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Explorer\AlwaysUnloadDLL и записать "1" в его параметр по умолчанию.

Отладка Add-in'ов к Visual C++

При отладке add-in'ов отладчику Visual C++ приходится отлаживать самого себя. Лучше всего запустить экземпляр среды Visual C++ без add-in'а, а затем использовать этот экземпляр для отладки. Иначе возможны весьма тонкие и неочевидные ошибки, на исправление которых уйдёт уйма времени. Другая возможность для отладки add-in'ов – удалённая отладка (о ней мы поговорим в следующем разделе).

Отладка ISAPI-расширений

ПРИМЕЧАНИЕ

Данные в этом разделе относятся к IIS5

ISAPI-расширение – это DLL, которая загружается веб-сервером IIS для обработки запросов. В зависимости от настроек защиты веб-приложения (application protection) они могут загружаться как главным файлом IIS inetinfo.exe (режим Low (IIS Process)), так и отдельным процессом dllhost.exe (режимы Medium (Pooled) и High (Isolated)). Чуть позже мы увидим, как отлаживать ISAPI-расширение в том и в другом случае. Но сначала несколько слов о подготовке расширения к отладке.

Подготовка к отладке

Прежде чем начинать отладку, рекомендуется проделать следующие шаги.

  1. Построить отладочную версию расширения.
  2. Создать для него виртуальную директорию с разрешением на выполнение (execute). Для создания виртуальной директории используется утилита Internet Services Manager (Запустить её можно из меню Start->Administrative Tools). Можно дать ей любое имя (например, test). В качестве физического пути к директории следует указать путь к отладочному каталогу DLL расширения (например, C:\Projects\MyISAPI\Debug).
  3. Отключить кэширование расширений веб-сервером. По умолчанию DLL расширения загружается сервером, как только приходит первый запрос к ней, а затем остаётся в памяти, чтобы последующие запросы обрабатывались быстрее. Это разумный подход, но в отладочных целях лучше отключить кэширование, чтобы DLL выгружалась сразу после обработки запроса. Для этого запустите Internet Services Manager, вызовите из контекстного меню веб-сайта диалог свойств, перейдите на закладку Home Directory, нажмите на кнопку Configuration... и снимите флажок Cache ISAPI applications.

В MSDN упоминается альтернативный способ отключить кэширование: открыть в редакторе реестра ключ HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W3SVC\Parameters и добавить в него параметр (REG_DWORD)CacheExtensions=0. Но мне не удалось заставить этот метод работать.

Если веб-сервер ещё не запущен, запустите его. После этого можно переходить непосредственно к отладке.

В процессе отладки ISAPI-расширений довольно часто приходится запускать и останавливать веб-сервер. Для этого можно использовать команды net start w3svc и net stop w3svc соответственно. При желании можно добавить эти команды в меню Tools, чтобы они всегда были под рукой.

Отладка расширения в режиме in-process

В этом режиме DLL загружается процессом inetinfo.exe. Чтобы к нему присоединиться, можно использовать любую из описанных в предыдущем разделе методик (команду Attach To Process, команду Debug в Task Manager или функцию DebugBreak, которую в данном случае следует вставить в GetExtensionVersion расширения). После этого можно действовать по сценарию, описанному в подразделе "Общие принципы отладки", чтобы загрузить отладочные символы (если это необходимо) и расставить точки останова.

Чтобы DLL получила управление, необходимо послать ей запрос. Это можно сделать из Internet Explorer. Запрос будет выглядеть примерно так: http://localhost/test/MyISAPI.dll.

Запуск IIS в режиме обыкновенного приложения

Если объем отладки велик, и часто приходится запускать и останавливать сервис, проще запускать IIS из отладчика, как обыкновенное приложение.

Чтобы заставить IIS работать в таком режиме, нужно изменить учетную запись, под которой запускаются сервисы IIS Admin, World Wide Web Publishing и FTP Publishing, на запись, под которой будет производится отладка. Физически при запуске всех этих сервисов запускается один и тот же исполняемый файл – inetinfo.exe. DLL-библиотеки загружаются в сервис World Wide Web Publishing, но он зависит от IIS Admin-сервиса, поэтому сервис IIS Admin должен быть запущен первым. Учетная запись, под которой теперь будут запускаться сервисы, должна иметь довольно высокие привилегии. Проще всего использовать для этого учетную запись администратора, добавив ей привилегию "Act as part of the operating system" (программистам известную как SE_TCB_NAME). Будьте осторожны, так как эта привилегия предоставляет широчайшие возможности. Теперь нужно настроить отладчик Visual C++, задав в качестве отлаживаемого проекта путь к файлу inetinfo.exe (по умолчанию он размещается в каталоге %SystemRoot%\System32\inetsrv\), а в качестве параметров строку "-e w3svc". Теперь при запуске проекта на отладку IIS будет загружаться автоматически. В начале очередного сеанса отладки не помешает убедиться, что сервис World Wide Web Publishing не был загружен именно как сервис (например, при перезагрузке системы).

Отладка расширения в режиме out-of-process

В этом режиме DLL загружается процессом dllhost.exe. Процесс отладки для него ничем принципиально не отличается от предыдущего случая. Помните только, что метод подключения к процессу с помощью DebugBreak не будет работать, так как исключение EXCEPTION_BREAKPOINT будет перехвачено внутри dllhost.exe.

В системе может быть несколько процессов с именем dllhost.exe. Необходимо выяснить, какой из них загружает DLL-расширения. Сделать это можно различными способами. Один из возможных вариантов – вставить в саму DLL код, сообщающий идентификатор процесса, в который она загружена. Например:

#define _WIN32_WINNT 0x0400
#include <windows.h>

...

#ifdef _DEBUG
    TCHAR szMessage [256];
    _stprintf(
        szMessage,
        _T("Please attach a debbuger to the process %u and click OK"),
        GetCurrentProcessId()
    );
    MessageBox(NULL, szMessage, _T("ISAPI debugging"),
               MB_OK|MB_SERVICE_NOTIFICATION);
#endif

Обратите внимание на флаг MB_SERVICE_NOTIFICATION. Он необходим, чтобы сообщение из ISAPI-расширения было видно на экране.


Эта статья опубликована в журнале RSDN Magazine #0. Информацию о журнале можно найти здесь