Создание VxD на Visual C++ без ассемблерных модулей - Статические и динамические драйверы

ОГЛАВЛЕНИЕ

 

Статические и динамические драйверы

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

Порядок загрузки статических драйверов

Статические драйверы загружаются системой в определенном порядке при этом основные драйверы должны загружаться первыми, а после этого — зависящие от них драйверы более высокого уровня. Для этой процедуры каждый драйвер имеет параметр Init Order — числовую константу, определяющую место драйвера в списке загрузки, которая происходит в порядке возрастания значений параметра. Системным драйверам назначены определенные значения, отражающие их зависимость друг от друга. Если порядок загрузки не имеет смысла — используется нулевое значение параметра; такие драйверы загружаются после завершения инициализации «номерных» VxD.

Системные сообщения драйверу

Система взаимодействует с драйвером путем передачи ему системных сообщений о загрузке/выгрузке драйвера, а также при наступлении определенных системных событий, которые могут потребовать вмешательства драйвера (создание/удаление виртуальной машины, приложения, задачи (thread), смена текущей виртуальной машины/задачи, перезагрузка системы, появление нового устройства и т.п.).

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

Сервисные функции драйвера

Каждый драйвер, имеющий идентификатор, может поддерживать набор сервисных функций, доступных для других VxD в системе. Если VxD представляет какое-либо виртуальное устройство, эти функции служат для управления устройством либо просто воплощают какие-либо операции, ради которых создавался драйвер.

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

Обязательна для поддержки только функция с нулевым номером — Get Version (запрос версии). Поддержка и назначение остальных функций оставлена на усмотрение разработчика драйвера.

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

Интерфейс с прикладными программами

Для взаимодействия с прикладными программами VxD может предоставлять три вида API (Application Program Interface — интерфейс прикладных программ):

  • V86 API — для 16-разрядных приложений DOS (программ режима V86).
  • PM API — для 16-разрядных приложений Windows, которые до появления Windows 9x назывались Protected Mode Applications (приложения защищенного режима).
  • Win32 API — для приложений Win32.

Для обработки запросов от 16-разрядных программ в драйвере предусматриваются две различные функции — для запросов от виртуальных машин DOS и для запросов от приложений Win16. Запросы от приложений Win32 передаются в виде системных сообщений их общему диспетчеру.

16-разрядные приложения получают доступ к своим API посредством функции 0x1684 программного прерывания 2F, которая возвращает адрес шлюза (gate) для вызова VxD. Поиск нужного драйвера возможен как по идентификатору, так и по имени; поиск по имени был введен позднее, поэтому документирован не во всех описаниях функции int 2F.

При выполнении вызова через шлюз происходит переключение в 32-разрядный режим с сохранением всех регистров вызвавшей виртуальной машины (клиента) в специальной структуре, после чего управление передается соответствующей процедуре обработки в VxD. При возврате происходит восстановление значений регистров, которые могут быть модифицированы процедурой обработки.

Приложения Win32 получают доступ к API посредством функции CreateFile, загружающей VxD, если он динамический, и открывающей его интерфейс. Поиск драйвера происходит по имени драйвера, имени его файла либо по имени ключа реестра, описывающего драйвер.

Обращение к обработчику Win32 API в драйвере происходит при вызове приложением функции DeviceIoControl. При этом выполняется переключение в режим ядра и передача диспетчеру системных сообщений драйвера сообщения W32_DEVICEIOCONTROL. Для обмена данными передаются два независимых указателя (буфер параметров и буфер результата), которые могут ссылаться и на одну и ту же область памяти. Если драйвер поддерживает механизм асинхронных (overlapped) операций, фактическое завершение операции может происходить независимо от момента возврата управления из диспетчера.