Автор: Александр Шаргин Источник: RSDN Magazine #0
Опубликовано: 27.01.2002 Исправлено: 13.03.2005 Версия текста: 1.0
Общие принципы отладки DLL
Хотя в виде DLL реализуются самые различные объекты, существует 2 общих принципа отладки, применимых ко всем разновидностям DLL.
Поскольку DLL не может выполняться сама по себе, для её отладки необходимо запустить под отладчиком любое использующее её приложение. Полный путь к exe-файлу этого приложения необходимо указать в настройках отладки.
Необходимо также проследить, чтобы при запуске приложения отладчик загружал отладочные символы нашей DLL. Иначе все точки останова, поставленные в коде DLL, будут отключены. По умолчанию символы загружаются только для тех DLL, которые подключаются при запуске приложения. Для всех остальных (к ним, в частности, относятся все внутрипроцессные COM-серверы) загрузка символов не производится. Если отлаживаемая DLL принадлежит к этой категории, для неё необходимо явно потребовать загрузку отладочных символов. Для этого следует добавить её в список Additional DLLs в настройках отладки.
Дальнейшая отладка DLL ничем принципиально не отличается от отладки приложений.
Иногда приложение, использующее DLL, само должно запускаться ещё одним приложением (именно такая ситуация имеет место с ISAPI-расширениями, которые загружает сервис IIS). В этом случае можно придерживаться следующей тактики.
Подключиться к приложению, используя методики из предыдущего раздела (в данном случае вызов DebugBreak придётся вставлять в код DLL). Если приложение продолжает выполнение, остановить его ( Debug->Break ).
Убедиться, что отладчик загрузил символы для DLL (в окне Debug должна появиться строчка вида «Loaded symbols for «). Если этого не произошло, следует добавить отлаживаемую DLL в список Additional DLLs .
Открыть файлы с исходными текстами DLL (не открывая её проекта!) и расставить необходимые точки останова.
Возобновить выполнение приложения.
Отладка расширений оболочки Windows
Для расширений оболочки Windows в качестве отлаживаемого приложения указывается explorer.exe .
Закрытие оболочки Windows
Поскольку в системе не могут работать две оболочки одновременно (об исключениях из этого правила мы поговорим немного позже), необходимо завершить оболочку Windows, прежде чем запускать новую из-под отладчика. Чтобы завершить оболочку, нужно:
Выбрать команду Start->Shut Down .
Щёлкнуть по кнопке No в раскрывшемся диалоге, удерживая клавиши Ctrl+Alt+Shift .
ПРИМЕЧАНИЕ
В Windows 2000 вместо кнопки No следует щёлкнуть по кнопке Cancel .
Повторный запуск оболочки
Чтобы снова запустить оболочку по окончании сеанса отладки, достаточно запустить explorer.exe из любой оболочки или из командной строки. Если ни оболочки, ни командной строки под рукой нет, можно использовать следующие приёмы.
Под Windows NT/2000:
Нажать Ctrl+Alt+Del.
Вызвать Task Manager.
Выбрать команду File->New Task (Run) и запустить оболочку.
Сделать двойной щелчок по рабочему столу. Откроется диалоговое окно Task .
Выбрать команду File->Run и запустить оболочку.
Отладка расширений в 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-расширение в том и в другом случае. Но сначала несколько слов о подготовке расширения к отладке.
Подготовка к отладке
Прежде чем начинать отладку, рекомендуется проделать следующие шаги.
Построить отладочную версию расширения.
Создать для него виртуальную директорию с разрешением на выполнение (execute). Для создания виртуальной директории используется утилита Internet Services Manager (Запустить её можно из меню Start->Administrative Tools ). Можно дать ей любое имя (например, test). В качестве физического пути к директории следует указать путь к отладочному каталогу DLL расширения (например, C:\Projects\MyISAPI\Debug ).
Отключить кэширование расширений веб-сервером. По умолчанию 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 код, сообщающий идентификатор процесса, в который она загружена. Например:
Обратите внимание на флаг MB_SERVICE_NOTIFICATION . Он необходим, чтобы сообщение из ISAPI-расширения было видно на экране.
Отладка библиотек DLL в Visual Studio (C#, C++, Visual Basic, F#) Debug DLLs in Visual Studio (C#, C++, Visual Basic, F#)
Библиотека DLL (библиотека динамической компоновки) — это библиотека, содержащая код и данные, которые могут использоваться несколькими приложениями. A DLL (dynamic-link library) is a library that contains code and data that can be used by more than one app. Visual Studio можно использовать для создания, сборки, настройки и отладки библиотек DLL. You can use Visual Studio to create, build, configure, and debug DLLs.
Создание библиотеки DLL Create a DLL
Создавать библиотеки DLL можно с помощью следующих шаблонов проектов Visual Studio. The following Visual Studio project templates can create DLLs:
Библиотека классов C#, Visual Basic или F# C#, Visual Basic, or F# Class Library
Библиотека элементов управления Windows Forms (WCF) C# или Visual Basic C# or Visual Basic Windows Forms Control (WCF) Library
Библиотека динамической компоновки (DLL) C++ C++ Dynamic-Link Library (DLL)
Дополнительные сведения см. в разделе Методы отладки MFC. For more information, see MFC debugging techniques.
Отладка библиотеки WCF аналогична отладке библиотеки классов. Debugging a WCF Library is similar to debugging a Class Library. Дополнительные сведения см. в статье Элементы управления Windows Forms. For details, see Windows Forms Controls.
Обычно библиотека DLL вызывается из другого проекта. You usually call a DLL from another project. При отладке вызывающего проекта в зависимости от конфигурации библиотеки DLL можно выполнить шаг с заходом и отладить код библиотеки DLL. When you debug the calling project, depending on the DLL configuration, you can step into and debug the DLL code.
Конфигурация отладки библиотеки DLL DLL debug configuration
При создании приложения на основе шаблона проекта Visual Studio Visual Studio Visual Studio автоматически создает требуемые параметры для конфигурации сборки отладки и выпуска. When you use a Visual Studio project template to create an app, Visual Studio Visual Studio automatically creates required settings for Debug and Release build configurations. При необходимости эти параметры можно изменить. You can change these settings if necessary. Дополнительные сведения см. в следующих статьях: For more information, see the following articles:
Установка DebuggableAttribute C++ Set C++ DebuggableAttribute
Чтобы отладчик мог присоединиться к библиотеке DLL C++, код C++ должен добавлять DebuggableAttribute . For the debugger to attach to a C++ DLL, the C++ code must emit DebuggableAttribute .
Установка DebuggableAttributeTo set DebuggableAttribute :
В обозревателе решений выберите проект DLL C++ и щелкните значок Свойства либо щелкните проект правой кнопкой мыши и выберите пункт Свойства. Select the C++ DLL project in Solution Explorer and select the Properties icon, or right-click the project and select Properties.
В области Свойства в разделе Компоновщик > Отладка выберите Да (/ASSEMBLYDEBUG) для свойства Отлаживаемая сборка. In the Properties pane, under Linker > Debugging, select Yes (/ASSEMBLYDEBUG) for Debuggable Assembly.
Дополнительные сведения см. в статье /ASSEMBLYDEBUG. For more information, see /ASSEMBLYDEBUG.
Задание расположений файлов DLL C/C++ Set C/C++ DLL file locations
Для отладки внешней библиотеки DLL вызывающий проект должен находить библиотеку DLL, ее PDB-файл и любые другие файлы, необходимые библиотеке DLL. To debug an external DLL, a calling project must be able to find the DLL, its .pdb file, and any other files the DLL requires. Вы можете создать пользовательскую задачу сборки, чтобы скопировать эти файлы в выходную папку
\Debug, или скопировать файлы вручную. You can create a custom build task to copy these files to your
\Debug output folder, or you can copy the files there manually.
Для проектов C/C++ можно задать расположения файлов заголовков и LIBD-файла на страницах свойств проекта, а не копировать их в выходную папку. For C/C++ projects, you can set header and LIB file locations in the project property pages, instead of copying them to the output folder.
Задание расположений файла заголовка C/C и LIB-файлаTo set C/C++ header and LIB file locations:
В обозревателе решений выберите проект DLL C/C++ и щелкните значок Свойства либо щелкните проект правой кнопкой мыши и выберите пункт Свойства. Select the C/C++ DLL project in Solution Explorer and select the Properties icon, or right-click the project and select Properties.
В верхней части области Свойства в разделе Конфигурация выберите Все конфигурации. At the top of the Properties pane, under Configuration, select All Configurations.
В разделе C/C++ > Общие > Дополнительные включаемые каталоги укажите папку с файлами заголовков. Under C/C++ > General > Additional Include Directories, specify the folder that has header files.
В разделе Компоновщик > Общие > Дополнительные каталоги библиотек укажите папку с LIB-файлами. Under Linker > General > Additional Libraries Directories, specify the folder that has LIB files.
В разделе Компоновщик > Ввод > Дополнительные зависимости укажите полный путь и имя файла для LIB-файлов. Under Linker > Input > Additional Dependencies, specify the full path and filename for the LIB files.
Нажмите кнопку ОК. Select OK.
Дополнительные сведения о параметрах проекта C++ см. в статье Справочник C++ по страницам свойств проекта Windows. For more information on C++ project settings, see Windows C++ property page reference.
Сборка отладочной версии Build a Debug version
Перед началом отладки обязательно создайте отладочную версию библиотеки DLL. Make sure to build a Debug version of the DLL before you start debugging. Для отладки библиотеки DLL вызывающее приложение должно находить PDB-файл и любые другие файлы, необходимые библиотеке DLL. To debug a DLL, a calling app must be able to find its .pdb file and any other files the DLL requires.
Вы можете создать пользовательскую задачу сборки, чтобы скопировать эти файлы DLL в выходную папку \Debug, или скопировать файлы вручную. You can create a custom build task to copy the DLL files to your \Debug output folder, or you can copy the files there manually.
Обязательно вызовите библиотеку DLL в правильном расположении. Make sure to call the DLL in its correct location. Это может показаться очевидным, но, если вызывающее приложение находит и загружает другую копию библиотеки DLL, отладчик никогда не достигнет заданных точек останова. This may seem obvious, but if a calling app finds and loads a different copy of the DLL, the debugger will never hit the breakpoints you set.
Отладка библиотека DLL Debug a DLL
Библиотеку DLL нельзя запускать напрямую. You can’t run a DLL directly. Ее должно вызывать приложение, обычно это EXE-файл. It must be called by an app, usually an .exe file. Дополнительные сведения см. в статье Проекты Visual Studio — C++. For more information, see Visual Studio projects — C++.
Чтобы отладить библиотеку DLL, можно начать отладку из вызывающего приложения или выполнить отладку из проекта DLL, указав вызывающее приложение. To debug a DLL, you can start debugging from the calling app, or debug from the DLL project by specifying its calling app. Можно также использовать окно «Интерпретация» отладчика для вычисления функций или методов DLL во время разработки без использования вызывающего приложения. You can also use the debugger Immediate window to evaluate DLL functions or methods at design time, without using a calling app.
Дополнительные сведения см. в статье Первое знакомство с отладчиком. For more information, see First look at the debugger.
Запуск отладки из вызывающего приложения Start debugging from the calling app
Вызывать библиотеку DLL могут следующие виды приложений. The app that calls a DLL can be:
Приложение из проекта Visual Studio Visual Studio в том же или другом решении из библиотеки DLL. An app from a Visual Studio Visual Studio project in the same or a different solution from the DLL.
Существующее приложение, которое уже развернуто и работает на тестовом или рабочем компьютере. An existing app that is already deployed and running on a test or production computer.
Программа расположена в Интернете и доступна по URL–адресу. Located on the web and accessed through a URL.
Веб-приложение с веб-страницей, которая внедряет библиотеку DLL. A web app with a web page that embeds the DLL.
Выполнить отладку библиотеки DLL из вызывающего приложения можно следующими способами. To debug a DLL from a calling app, you can:
Откройте проект для вызывающего приложения и начните отладку, выбрав Отладка > Начать отладку или нажав клавишу F5. Open the project for the calling app, and start debugging by selecting Debug > Start Debugging or pressing F5.
Выполните присоединение к приложению, которое уже развернуто и работает на тестовом или рабочем компьютере. Attach to an app that is already deployed and running on a test or production computer. Используйте этот вариант для библиотек DLL на веб-сайтах или в веб-приложениях. Use this method for DLLs on websites or in web apps. Дополнительные сведения см. в разделе Практическое руководство. Присоединение к выполняемому процессу. For more information, see How to: Attach to a running process.
Перед запуском отладки этого вызывающего приложения нужно установить точку останова в DLL. Before you start debugging the calling app, set a breakpoint in the DLL. См. статью Использование точек останова. See Using breakpoints. При попадании в точку останова DLL можно пошагово проходить по коду, наблюдая действия в каждой строке. When the DLL breakpoint is hit, you can step through the code, observing the action at each line. Дополнительные сведения см. в статье Навигация по коду с помощью отладчика. For more information, see Navigate code in the debugger.
Во время отладки в окне Модули можно проверить библиотеки DLL и EXE-файлы, загружаемые приложением. During debugging, you can use the Modules window to verify the DLLs and .exe files the app loads. Чтобы открыть окно Модули, во время отладки выберите Отладка > Окна > Модули. To open the Modules window, while debugging, select Debug > Windows > Modules. Дополнительные сведения см. в разделе Практическое руководство. использовать окно модулей. For more information, see How to: Use the Modules window.
Использование окна «Интерпретация» Use the Immediate window
Окно Интерпретация можно использовать для вычисления функций или методов DLL во время разработки. You can use the Immediate window to evaluate DLL functions or methods at design time. Окно Интерпретация выполняет роль вызывающего приложения. The Immediate window plays the role of a calling app.
Окно Интерпретация можно использовать во время разработки с большинством типов проектов. You can use the Immediate window at design time with most project types. Оно не поддерживается для SQL, веб-проектов или скриптов. It’s not supported for SQL, web projects, or script.
Например, чтобы протестировать метод с именем Test в классе Class1 , выполните следующие действия. For example, to test a method named Test in class Class1 :
Откройте проект DLL, откройте окно Интерпретация, последовательно выбрав пункты Отладка > Окна > Интерпретация или нажав сочетание клавиш CTRL+ALT+I. With the DLL project open, open the Immediate window by selecting Debug > Windows > Immediate or pressing Ctrl+Alt+I.
Создайте объект типа Class1 , введя следующий код C# в окне Интерпретация и нажав клавишу ВВОД. Instantiate an object of type Class1 by typing the following C# code in the Immediate window and pressing Enter. Этот управляемый код работает для C# и Visual Basic с соответствующими изменениями синтаксиса. This managed code works for C# and Visual Basic, with appropriate syntax changes:
В C# все имена должны быть указаны полностью. In C#, all names must be fully qualified. Когда языковая служба пытается вычислить выражение, все методы или переменные должны находиться в текущей области и контексте. Any methods or variables must be in the current scope and context when the language service tries to evaluate the expression.
Предположим, что Test принимает один параметр int , вычислим Test с помощью окна Интерпретация : Assuming that Test takes one int parameter, evaluate Test using the Immediate window:
Результат будет выведен в окне Интерпретация. The result prints in the Immediate window.
Можно продолжить отладку Test , установив в нем точку останова, а затем снова вычислив эту функцию. You can continue to debug Test by placing a breakpoint inside it, and then evaluating the function again.
Будет достигнута точка останова и можно будет пошагово пройти Test . The breakpoint will be hit, and you can step through Test . После выполнения Test , отладчик вернется в режим разработки. After execution has left Test , the debugger will be back in design mode.
Отладка в смешанном режиме Mixed-mode debugging
Вы можете написать вызывающее приложение для библиотеки DLL в управляемом или машинном коде. You can write a calling app for a DLL in managed or native code. Если собственное приложение вызывает управляемую библиотеку DLL и вы хотите выполнить отладку этих двух объектов, можно включить управляемые и машинные отладчики в свойствах проекта. If your native app calls a managed DLL and you want to debug both, you can enable both the managed and native debuggers in the project properties. Точный способ выполнения этой операции зависит от того, откуда будет начата отладка: из проекта DLL или из проекта вызывающего приложения. The exact process depends on whether you want to start debugging from the DLL project or the calling app project. Дополнительные сведения см. в разделе Практическое руководство. Отладка в смешанном режиме. For more information, see How to: Debug in mixed mode.
Можно выполнить отладку собственной библиотеки DLL из управляемого вызывающего проекта. You can also debug a native DLL from a managed calling project. Дополнительные сведения см. в статье об отладке управляемого и машинного кода. For more information, see How to debug managed and native code.