В Windows, так же как и в DOS, существует еще один вид исполняемых файлов - драйверы устройств. Windows 3.хх и Windows 95 используют одну модель драйверов, Windows NT - другую, a Windows 98 - уже третью, хотя и во многом близкую к модели Windows NT. В Windows 3.хх/95 применяются два типа драйверов устройств - виртуальные драйверы (VxD), выполняющиеся с уровнем привилегий 0 (обычно имеют расширение .386 для Windows 3.хх и .VXD для Windows 95), и непривилегированные драйверы, исполняющиеся, как и обычные программы, с уровнем привилегий 3 (как правило, они имеют расширение .DRV). Windows NT использует несовместимую модель драйверов, так называемую kernel-mode (режим ядра). На основе модели kernel-mode с добавлением поддержки технологии PNP и понятия потоков данных в 1996 году была создана модель WDM (win32 driver model), которая теперь используется в Windows 98/NT и, по-видимому, будет играть главную роль в дальнейшем.
Как и следовало ожидать, основным средством создания драйверов является ассемблер, и хотя использование С здесь возможно (в отличие от драйверов DOS), но сделать это сложнее: функции, к которым обращается драйвер, могут передавать параметры в регистрах; сегменты, из которых состоит драйвер, должны называться определенным образом и т. д. При создании драйверов часто пользуются одновременно С и ассемблером или С и специальным пакетом, который включает в себя все необходимые для инициализации средства.
Чтобы самостоятельно создавать драйверы для любой версии Windows, необходим комплект программ, документации, включаемых файлов и библиотек, распространяемый Microsoft, который называется DDK - Drivers Development Kit. (DDK для Windows NT/98 распространяются бесплатно.)
Чтобы создать драйвер, лучше всего начать с одного из прилагающихся примеров и изменять/добавлять процедуры инициализации, обработчики сообщений, прерываний и исключении, обработчики для API, предоставляемого драйвером, и т. д. Рассмотрим, как выглядит исходный текст драйвера, потому что он несколько отличается от привычных ассемблерных программ.
Любой драйвер начинается с директивы include vmm.inc, которая включает файл, содержащий определения используемых сегментов и макроопределений.
Макроопределения вида VXD_LOCKED_CODE_SEG/VXD_ LOCKED_CODE_ ENDS соответствуют директивам начала и конца сегментов (в данном случае сегмента _LTEXT). Другие важные макроопределения - Declare_Virtual_Device и VMMCall/WDMCall. Первое - просто определение, получающее в качестве параметров идентификатор драйвера, название, версию, порядок загрузки и адреса основных процедур драйвера, из которых строится его заголовок. Второе - замена команды call, получающая в качестве параметра имя функции VMM или WDM, к которой надо обратиться.