Выбрать главу

DriverNetworks — используется для разработки драйверов сетевых устройств. Если не предполагается разработка такого драйвера, данный компонент не является необходимым.

Для инсталляции DS на компьютере необходимо проинсталлировать пакет DDK и среду VC++. После этого можно начинать инсталляцию DS. Сама инсталляция проста и не отличается от процесса инсталляции того же VC++, например. По умолчанию пакет ставится в папку C:\Program Files\NuMega\DriverStudio. Знание пути к DS необходимо для дальнейшей работы с программой. В дальнейшем мы будем его называть <путь_к_DS>. При первом запуске DS необходимо скомпилировать библиотеки, необходимые для работы. Для этого следует запустить среду VC++ и открыть проект <путь_к_DS>\DriverVorks\source\vdwlibs.dsw. Вся суть в том, что DS использует собственную библиотеку классов для написания драйвера. Эта библиотека поставляется в исходных кодах, подобно библиотеке MFC или библиотекам под UNIX. Поэтому теперь необходимо откомпилировать с помощью VC++ данный проект.

Стоит сразу проверить опции проекта и установить активную конфигурацию VdwLibs — Win32 WDM Checked (если планируется отлаживать скомпилированные драйвера) или Win32 WDM Free. Теперь запускаем проект на компиляцию. В результате в папке <путь_к_DS>\DriverVorks\lib\i386\checked появляется библиотека vdw.lib (при использовании ОС win2K) или vdw_wdm.lib (win 9x). DS готов к работе.

2.1. Система классов DriverWorks.

Возможно, идея писать драйвера объектно-ориентированными и кажется на первый взгляд нелогичной. Но при более близком знакомстве с DriverStudio и с драйверами в общем, оказывается, что это не так уж страшно и довольно удобно. Объектная модель DriverWorks отражает архитектуру WDM и представляет собой систему классов, построенную на системных вызовах. Цель DriverWorks – с одной стороны, оставаться на достаточно низком уровне программирования, чтобы эффективно писать драйвера, а с другой – упростить и упорядочить процесс разработки драйверов режима ядра.

В соответствии с идеологией DriverWorks драйвер представляется, как набор объектов. Эта же идея присутствует и в "чистой" архитектуре WDM, но DriverWorks упорядочивает эти объекты и представляет их экземплярами классов. Классы DriverWorks также несколько упрощают код драйвера по сравнению с DDK, делают его более компактным и доступным для понимания. Часто повторяющиеся, рутинные фрагменты кода драйвера спрятаны внутри методов класса. И то, что при использовании пакета DDK занимало несколько строк в программе, теперь можно вполне заменить вызовом одного единственного метода.

Также в DriverWorks предложено несколько полезных классов: например класс KFile — доступ к файлам или классы динамических списков и массивов.

В общем, сама идея DriverWorks напоминает Visual C++ и библиотеку MFC. MFC представляет из себя некую прослойку, которая отделяет программиста от жутковатых функций API и позволяет создавать объектно-ориентированные проекты, при этом оставаясь на достаточно низком уровне программирования.

Впрочем, в системе классов DriverWorks есть одна особенность: иерархия классов практически отсутствует. Это вполне естественно: в системе классов DriverWorks присутствуют самые различные классы — классы, представляющие собой ресурсы устройства (линии ПДП, прерываний, областей памяти, портов ввода-вывода), сами устройства, классы для взаимодействия с реестром, файлами и т.п. Еще одним аргументом в пользу отсутствия наследования является то, что разветвленная иерархия классов может снизить быстродействие программы. Для драйвера, это, конечно, неприемлемо.

В основе архитектуры DriverWorks лежит несколько основных классов.

Объект драйвера (Driver Object).

Объект драйвера является экземпляром класса KDriver. Он представляет драйвер в целом как некую абстракцию. Для объекта драйвера абсолютно все равно, каким оборудованием он управляет, объект драйвера об этом по настоящему никогда не задумывается. Его задача — обеспечить интерфейс драйвера с ОС: загрузка и инициализация драйвера, выгрузка и т.п. А управление аппаратурой возлагается на другие объекты драйвера, в частности, на объект устройства.

Когда ОС загружает драйвер, то она создает для него соответствующий объект драйвера. Компонент ядра операционной системы — диспетчер ввода-вывода (I/O Manager) — использует объекты драйверов для управления устройствами. Каждый драйвер отвечает за управление одним или несколькими объектами устройств. Запрос на операцию ввода-вывода (I/O request), посланный приложением пользователя, поступает к диспетчеру ввода-вывода.

Диспетчер ввода-вывода определяет, какой именно объект драйвера отвечает за соответствующий объект устройства, и перенаправляет ему запрос. Кроме управления объектами устройств, объект драйвера имеет дополнительные методы, отвечающие за инициализацию и завершение работы драйвера. Программист создает свой подкласс класса KDriver для взаимодействия с системой. Он обязательно должен содержать метод DriverEntry — функцию, вызываемую при инициализации драйвера.

В отличие от обычного не-WDM драйвера, процедура инициализации WDM-драйвера выполняет весьма ограниченное число функций: в основном это загрузка некоторых внутренних переменных на основе данных реестра. WDM-драйвер не инициализирует ресурсы устройства при старте в вызове EntryPoint. Для этого существует объект устройства.

WDM-драйвер экспортирует метод AddDevice, который вызывается системой, если обнаружено устройство, поддерживаемое данным драйвером. Этот метод отвечает за создание объектов устройств, соответствующих системным физическим объектам устройств (Physical Device Object, PDO).

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

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

Класс KRegistryKey

Как было упомянуто выше, драйвер обращается к системному реестру при инициализации. Системный реестр (registry) — системная база данных, организованная в виде дерева, похожего на дерево каталогов. Каждую ветвь этого дерева (реестра) называют разделом (key), каждый лист – параметром (value). Данные, хранящиеся в реестре, могут быть разных типов: целое (integer), строка, набор байтов.

Система позволяет каждому драйверу хранить данные в реестре. Эти данные используются драйверами при старте и инициализации. Обычно драйвер хранит данные в разделе HKLM\SYSTEM\CurrentControlSet\Services\<имя драйвера>\Parameters\.

В DriverWorks есть класс KRegistryKey, который облегчает доступ к параметрам реестра. Он имеет методы для чтения (QueryValue), записи (WriteValue), удаления (Delete) значений ключей реестра. При вызове конструктора KRegistryKey сразу указывается ключ, с которым будет связан создаваемый объект. Далее можно изменить ключ при помощи метода Reconstruct.

Объект запроса на ввод-вывод (I/O Request Object)

Объекты запроса на ввод-вывод, более известные, как пакеты запроса на ввод-вывод (I/O request packet, IRP — так мы и будем их называть в дальнейшем), предназначены для управления драйверами режима ядра.

Физически IRP представляет собой весьма сложную структуру данных, содержащую множество полей, таких как код статуса, указатель на буфер пользователя, указатель на IRP драйвера более высокого уровня, различные флаги и т.п. Многие из этих полей не используется драйверами режима ядра, но необходимы для того, чтобы IRP был функционально полным инструментом управления драйверами. Т.е. при помощи IRP можно управлять любым типом драйвера. При желании увидеть структуру IRP во всем ее великолепии — см. Win2000 DDK.