Программный интерфейс драйвера
Далее, вслед за управляющей процедурой VXDSRV_Control, обеспечивающей обработку системного сообщения Sys_Crit_Init, в исходном тексте драйвера находится таблица адресов функций программного интерфейса драйвера VXDSRV_API_Call.
В этой таблице находятся адреса трех функций, предназначенных для вызова из виртуальных машин MS-DOS и системной виртуальной машины. Эти функции являются интерфейсом между драйвером с одной стороны, и виртуальными машинами, с другой стороны.
Функция vxdapiGetVersion позволяет определить версию нашего виртуального драйвера. Абсолютно любой виртуальный драйвер должен иметь в составе своего интерфейса эту функцию, причем она должна иметь номер, равный 0 (т. е. при ее вызове в регистр AX необходимо загрузить нулевое значение).
Функции vxdapiRegisterWnd и vxdapiUnregisterWnd предназначены, соответственно, для регистрации и отмены регистрации главного окна приложения dos2win.exe, а также буфера и функции обратного вызова DLL-библиотеки d2w.dll в виртуальном драйвере. Регистрация заключается в том, что драйвер сохраняет адрес функции обратного вызова и буфера в своих глобальных переменных.
Имена процедур VXDSRV_V86API_Handler и VXDSRV_PMAPI_Handler описаны в макрокоманде определения драйвера. Эти процедуры получают управление при вызове драйвера, соответственно, из виртуальной машины MS-DOS и системной виртуальной машины. Их задачей является установка флага V86CallFlag, который может быть проанализирован при необходимости определения типа виртуальной машины, из которой сделан вызов - системной или виртуальной машины MS-DOS.
После установки флага обе процедуры вызывают процедуру VXDSRV_API_Handler. Ее задачей является анализ содержимого регистра AX вызывающей виртуальной машины и передача управления на соответствующую процедуру по таблице адресов функций программного интерфейса драйвера VXDSRV_API_Call.
Обратите внимание, что анализируется не текущее содержимое регистра AX, а содержимое регистра AX виртуальной машины, взятое из структуры, адрес которой передается через регистр EBP.
Напомним, что в этой структуре сохраняется текущий контекст виртуальной машины на момент вызова виртуального драйвера.
Займемся теперь программным интерфейсом драйвера VXDSRV.
Процедура vxdapiGetVersion - самая простая. Она возвращает версию драйвера в регистре AX вызывающей виртуальной машины. Заметьте, что процедура не просто записывает номер версии в регистр AX, а изменяет соответствующее поле структуры контекста вызывающей виртуальной машины.
Процедура vxdapiRegisterWnd регистрирует окно приложения dos2win.exe. Эту процедуру можно вызывать только в защищенном режиме, поэтому анализируется флаг V86CallFlag.
Селектор и смещение функции обратного вызова, расположенной в DLL-библиотеке, передается этой процедуре через регистры DX и CX. Виртуальный драйвер сохраняет эти значения в глобальных переменных CallbackSel и CallbackOff.
Помимо адреса функции обратного вызова, виртуальный драйвер сохраняет адрес буфера, предназначенного для записи параметров запускаемого приложения Windows. Этот адрес передается в регистрах SI:DI.
Но драйвер работает в модели памяти FLAT, поэтому для обеспечения доступа к буферу со стороны драйвера необходимо преобразовать адрес из формата <селектор:смещение> во FLAT-адрес. Проще всего сделать это с помощью сервиса Map_Flat.
Перед вызовом этого сервиса в регистр AH необходимо загрузить смещение поля структуры контекста виртуальной машины, содержащего селекторную (или сегментную) компоненту адреса, а в регистр AL - смещение поля, содержащего компоненту смещения. Сервис Map_Flat выполнит все необходимые преобразования, причем будет приниматься во внимание тип виртуальной машины. Для виртуальной машины MS-DOS будет выполнено преобразование из формата <сегмент:смещение>, а для системной виртуальной машины - из формата <селектор:смещение>.
Результат преобразования будет записан в регистр EAX.
При регистрации виртуальный драйвер создает семафор с начальным значением, равным 1. Этот семафор будет использован для исключения реентерабельных вызовов одной из процедур драйвера.
Семафоры создаются сервисом Create_Semaphore. Начальное значение семафора задается содержимым регистра ECX перед вызовом сервиса. Идентификатор созданного семафора возвращается в регистре EAX. Его необходимо сохранить для выполнения операций над семафором.
Процедура vxdapiUnregisterWnd отменяет регистрацию. Она записывает нулевые значения в глобальные переменные, содержащие адреса функции обратного вызова и буфера, которые находятся в DLL-библиотеке d2w.dll, а также уничтожает созданный при регистрации семафор, вызывая сервис Destroy_Semaphore. Идентификатор уничтожаемого семафора передается через регистр EAX.