Операционная система Microsoft Windows 3.1 для программиста. Дополнительные главы© Александр Фролов, Григорий ФроловТом 17, М.: Диалог-МИФИ, 1994, 287 стр. 5.3. Загружаемые драйверыВ этом разделе мы расскажем вам о последнем, третьем типе драйверов Windows. Это так называемые загружаемые или инсталлируемые драйверы (installable drivers). Как мы уже говорили, загружаемые драйверы - это обычные DLL-библиотеки, которые экспортируют функцию с именем DriverProc. Обычные приложения Windows и обычные DLL-библиотеки могут выполнять различные операции с загружаемыми драйверами, такие как открытие и закрытие, активизация и перевод в неактивное состояние. В программном интерфейсе Windows определены несколько функций, с помощью которых можно обращаться к загружаемым драйверам. Кроме того, предусмотрен стандартный механизм инсталляции и конфигурирования загружаемых драйверов с помощью пиктограммы Drivers приложения Control Panel. Функции для работы с загружаемыми драйверамиПеред обращением к загружаемому драйверу его необходимо открыть функцией OpenDriver: HDRVR OpenDriver( LPCSTR lpDriverName, // имя драйвера LPCSTR lpSectionName, // имя секции ini-файла LPARAM lParam); // адрес дополнительных данных Займемся параметрами этой функции. В процессе инсталляции устанавливаемого драйвера в секции [drivers] файла system.ini для каждого драйвера создается отдельная строка: [drivers] Wave=galaxy.drv MIDI=galaxy.drv AUX=sgaux.drv WAST=wastdrv.dll Эти строки устанавливают соответствие между именем загружаемого драйвера и именем файла, содержащего загрузочный модуль драйвера. Дополнительно после имени файла могут указываться параметры, отделенные символом пробела. Драйвер записывается в системный каталог Windows. В качестве параметра lpDriverName для функции OpenDriver следует указывать имя драйвера, как оно определено в секции [drivers], или имя файла, содержащего драйвер. Параметр lpSectionName позволяет загрузить драйвер, описанный в произвольной секции файла system.ini. Если же используется стандартная секция [drivers], этот параметр нужно указать как NULL. В процессе открытия драйвера функция DriverProc вызывается несколько раз для обработки инициализирующих сообщений. При этом она через один из своих параметров получает значение, указанное в параметре lParam функции OpenDriver. При нормальном завершении функция OpenDriver возвращает идентификатор драйвера, который следует сохранить для последующих обращений к драйверу. После завершения работы с драйвером его необходимо закрыть функцией CloseDriver: LRESULT CloseDriver( HDRVR hdrvr, // идентификатор драйвера LPARAM lParam1, // дополнительные данные 1 LPARAM lParam2); // дополнительные данные 2 В процессе закрытия драйвера, как и при его открытии, функция DriverProc вызывается несколько раз для обработки завершающих сообщений. При этом она через свои параметры получает значения, указанные в параметрах lParam1 и lParam2 функции CloseDriver. Для взаимодействия с загружаемым драйвером приложения Windows и DLL-библиотеки используют функцию SendDriverMessage, которая посылает сообщение функции DriverProc. Приведем прототип функции SendDriverMessage: LRESULT SendDriverMessage( HDRVR hdrvr, // идентификатор драйвера UINT msg, // код сообщения LPARAM lParam1, // первый параметр LPARAM lParam2); // второй параметр Функция DriverProcПриведем прототип функции DriverProc, обрабатывающей сообщения, посылаемые загружаемому драйверу: LRESULT CALLBACK _export DriverProc( DWORD dwDiverId, // идентификатор драйвера HDRVR hDriver, // идентификатор, который // используется для обращения к драйверу UINT msg, // код сообщения LPARAM lParam1, // первый параметр сообщения LPARAM lParam2) // второй параметр сообщения Функция DriverProc напоминает другую хорошо известную вам функцию обратного вызова, а именно, функцию окна WndProc. Функция DriverProc обрабатывает ряд сообщений, которые мы опишем в следующем разделе. Все необработанные сообщения должны посылаться функции DefDriverProc. Назначение параметров этой функции аналогично назначению параметров функции DriverProc. Сообщения для драйвераПри инициализации загружаемый драйвер получает последовательно три сообщения: DRV_LOAD, DRV_ENABLE и DRV_OPEN (именно в этом порядке). Сообщение DRV_LOAD, как и можно было бы ожидать, посылается тогда, когда драйвер загружен в память. Для продолжения загрузки драйвера в память соответствующий обработчик должен вернуть значение 1L. Сообщение DRV_ENABLE в расширенном режиме работы Windows посылается один раз в процессе инициализации. В стандартном режиме пользователь может переключаться время от времени на работу с программами MS-DOS, при этом драйвер получает сообщение DRV_DISABLE. Когда же пользователь вновь возвращается к работе с приложениями Windows, драйвер получает сообщение DRV_ENABLE. Последним при открытии драйвер получает сообщение DRV_OPEN, в ответ на которое обработчик должен вернуть значение 1L (в противном случае операция открытия драйвера не будет выполнена). При закрытии драйвера функция DriverProc получит последовательно сообщения DRV_CLOSE, DRV_DISABLE и DRV_FREE. Обработчики этих сообщений должны освободить ресурсы, занимаемые драйвером. Когда пользователь выполняет установку загружаемого драйвера с помощью приложения Control Panel, функция DriverProc получает сообщение DRV_INSTALL. Обработчик этого сообщения может выполнить необходимые инициализирующие действия, например, создание разделов в файле system.ini или в других конфигурационных файлах. Далее драйвер получает сообщение DRV_QUERYCONFIGURE. С помощью этого сообщения приложение Control Panel определяет, поддерживает ли данный драйвер функцию настройки конфигурации. Если такая функция поддерживается, обработчик сообщения DRV_QUERYCONFIGURE должен вернуть значение 1L, в противном случае - значение 0L. При необходимости изменения конфигурации (и если драйвер поддерживает такую возможность) драйвер получает сообщение DRV_CONFIGURE. Это сообщение посылается при установке драйвера, а также когда пользователь изменяет конфигурацию драйвера с помощью приложения Control Panel. В ответ на сообщение DRV_CONFIGURE драйвер обычно выводит диалоговую панель, с помощью которой пользователь может выполнить настройку параметров драйвера. В любой момент времени загружаемый драйвер может быть удален из системы. Такая возможность предусмотрена в приложении Control Panel. В этом случае драйвер получит сообщение DRV_REMOVE, в ответ на которое он может внести соответствующие изменения в файлы конфигурации. Загружаемый драйвер может получать и другие сообщения, которые мы не будем рассматривать для экономии места. Полное описание вы можете найти в документации, которая поставляется вместе с SDK (именно SDK, а не DDK, как это можно было бы ожидать). Для организации взаимодействия между приложением и загружаемым драйвером можно использовать пользовательские сообщения, код которых должен быть больше DRV_RESERVED, но меньше DRV_USER. Эти две константы описаны в файле windows.h. Драйвер WASTDRV.DLLЗагружаемый драйвер часто используется в качестве альтернативы DLL-библиотеки. Мы подготовили исходный текст загружаемого драйвера wastdrv.dll (листинг 5.12), который предназначен для совместной работы с описанным ранее виртуальным драйвером vxdsrv.386 и приложением wast.exe, которое будет описано позже. Драйвер wastdrv.dll решает те же задачи, что и DLL-библиотека d2w.dll, однако теперь появилась возможность удобной установки всего комплекса и его включения/отключения с помощью стандартных средств Control Panel. Итак, обратимся к исходному тексту драйвера. Листинг 5.12. Файл wast\wastdrv.cpp // ====================================================== // Загружаемый драйвер wastdrv.dll // Версия 1.0 // Используется совместно с приложением wast.exe // и VxD-драйвером VXDSRV.386 версии 1.1 // ------------------------------------------------------ // Copyright (C) 1995 Alexandr Frolov // ====================================================== #define STRICT #include <windows.h> #include <mem.h> #include <string.h> #include "wastdrv.hpp" #include "wastvxd.hpp" extern "C" LRESULT CALLBACK _export DriverProc(DWORD dwDiverId, HDRVR hDriver, UINT msg, LPARAM lParam1, LPARAM lParam2); extern "C" void FAR PASCAL _export WinAppStart(WORD wVxDVersion); BOOL RegisterTask(HTASK hTask); void UnregisterTask(VXDAPI vxdEntry); int CALLBACK _export DlgProc(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam); void AutoStartWAST(BOOL); DWORD dwRc = 0L; // Точка входа API VxD-драйвера VXDAPI vxdApi = NULL; // Идентификатор задачи приложения wast.exe HTASK hTaskWAST = NULL; // Буфер для передачи информации о запукаемой // программе BYTE szCallbackBuf[350]; // Очередь запросов на запуск программ из VM MS-DOS BYTE szCmd[6][350]; // Номер строки параметров в массиве szCmd int nCmdLine = 0; // Флаг регистрации приложения wast.exe BOOL fTaskRegistered = FALSE; HINSTANCE hMod; char szDriverName[] = "wastdrv"; char szTemp[80]; // ======================================================== // Функция LibMain // ======================================================== #pragma argsused int FAR PASCAL LibMain(HINSTANCE hModule, WORD wDataSegment, WORD wHeapSize, LPSTR lpszCmdLine) { hMod = hModule; // Получаем точку входа API VxD-драйвера vxdApi = vxdGetDeviceAPI(VXD_ID); return TRUE; } // ======================================================== // Функция WEP // ======================================================== #pragma argsused int FAR PASCAL WEP(int bSystemExit) { // Если выгружается из памяти DLL-библиотека, // содержащая загружаемый драйвер, // выполняем отключение VxD-драйвера if(vxdApi != NULL) { if(fTaskRegistered) UnregisterTask(vxdApi); } return 1; } // ======================================================== // Функция обратного вызова WinAppStart // ======================================================== extern "C" void FAR PASCAL _export WinAppStart(WORD wVxDVersion) { if(wVxDVersion != 0x0101) return; _fmemcpy((LPVOID)szCmd[nCmdLine], (LPVOID)szCallbackBuf, 65 + 256); PostAppMessage(hTaskWAST, WM_STARTWINAPP, 0, (LPARAM)szCmd[nCmdLine]); nCmdLine++; if(nCmdLine > 5) nCmdLine = 0; } // ======================================================== // Функция RegisterTask // Регистрация приложения wast.exe // ======================================================== BOOL RegisterTask(HTASK hTask) { if(vxdApi == NULL) return FALSE; // Устанавливаем флаг регистрации fTaskRegistered = TRUE; // Сохраняем идентификатор окна hTaskWAST = hTask; // Вычисляем компоненты адреса функции обратного вызова unsigned sel = SELECTOROF((LPVOID)WinAppStart); unsigned off = OFFSETOF((LPVOID)WinAppStart); // Вычисляем компоненты адреса буфера szCallbackBuf unsigned bsel = SELECTOROF(szCallbackBuf); unsigned boff = OFFSETOF(szCallbackBuf); // Регистрируем функцию обратного вызова и // буфер szCallbackBuf в VxD-драйвере asm mov dx, sel asm mov cx, off asm mov si, bsel asm mov di, boff asm mov ax, vxdapiRegisterTask (*vxdApi)(); return TRUE; } // ======================================================== // Функция UnregisterTask // Отключение VxD-драйвера // ======================================================== void UnregisterTask(VXDAPI vxdEntry) { if(vxdApi == NULL) return; // Сбрасываем флаг регистрации fTaskRegistered = FALSE; asm mov ax, vxdapiUnregisterTask (*vxdEntry)(); } // ======================================================== // Функция vxdGetDeviceAPI // Получение адреса точки входа API для // VxD-драйвера, идентификатор которого // задан параметром vxd_id // ======================================================== VXDAPI vxdGetDeviceAPI(unsigned short vxd_id) { unsigned axreg, dxreg; asm push ax asm push bx asm push di asm push es asm mov ax, 0x1684 asm mov bx, vxd_id asm xor di, di asm mov es, di asm int 0x2f asm mov ax, di asm mov dx, es asm pop es asm mov axreg, ax asm mov dxreg, dx asm pop di asm pop bx asm pop ax return((VXDAPI)MAKELP(dxreg, axreg)); } // ======================================================== // DriverProc // Функция загружаемого драйвера // ======================================================== extern "C" LRESULT CALLBACK _export DriverProc( DWORD dwDiverId, // идентификатор драйвера HDRVR hDriver, // идентификатор, который // используется для обращения к драйверу UINT msg, // код сообщения LPARAM lParam1, // первый параметр сообщения LPARAM lParam2) // второй параметр сообщения { switch(msg) { // Регистрация окна приложения wast.exe case UDRV_REGISTERTASK: { // Если виртуальный драйвер не загружен, // возвращаем признак ошибки FALSE if(vxdApi == NULL) { dwRc = (DWORD)FALSE; break; } // Выполняется только в том случае, если // разрешен запуск приложений Windows из // командной строки MS-DOS if(GetPrivateProfileInt(szDriverName, "Enable", 0, "system.ini")) { dwRc = (DWORD)RegisterTask((HTASK)lParam1); } break; } // Отмена регистрации приложения wast.exe case UDRV_UNREGISTERTASK: { if(fTaskRegistered) UnregisterTask(vxdApi); break; } // Загрузка драйвера. Это первое сообщение, которое // получает драйвер case DRV_LOAD: { dwRc = 1l; break; } // Это сообщение посылается драйверу перед тем, // как драйвер будет выгружен из памяти case DRV_FREE: { dwRc = 1l; break; } // Открытие драйвера case DRV_OPEN: { dwRc = 1l; break; } // Закрытие драйвера case DRV_CLOSE: { dwRc = 1l; break; } // Разблокирование драйвера case DRV_ENABLE: { dwRc = 1l; break; } // Блокирование драйвера case DRV_DISABLE: { dwRc = 1l; break; } // Это сообщение посылается при установке драйвера case DRV_INSTALL: { // Создаем раздел [wastdrv] в файле system.ini // В этом разделе создаем строку: "Enable=1" WritePrivateProfileString(szDriverName, "Enable", "1", "system.ini"); // Дописываем имя приложения wast.exe в строке // "load=" раздела [windows] файла win.ini AutoStartWAST(TRUE); // Запрашиваем перезапуск Windows dwRc = DRVCNF_RESTART; break; } // Удаление драйвера case DRV_REMOVE: { // Если окно приложения wast.exe было // зарегистрировано, отменяем регистрацию if(fTaskRegistered) UnregisterTask(vxdApi); // Посылаем приложению wast.exe сообщение // WM_UNLOADWAST, в ответ на которое оно // завершает свою работу if(hTaskWAST != NULL) PostAppMessage(hTaskWAST, WM_UNLOADWAST, 0, 0l); // Идентификатор задачи wast.exe теперь // недействителен hTaskWAST = NULL; // В разделе [wastdrv] файла system.ini // заменяем строку "Enable=1" на "Enable=0" WritePrivateProfileString(szDriverName, "Enable", "0", "system.ini"); // Отменяем автоматический запуск wast.exe AutoStartWAST(FALSE); dwRc = 0l; break; } // Это сообщение присылается как запрос на // возможность конфигурирования драйвера. // Так как наш драйвер можно конфигурировать, // возвращаем значение 1l case DRV_QUERYCONFIGURE: { dwRc = 1l; break; } // Конфигурирование драйвера case DRV_CONFIGURE: { // Создаем диалоговую панель конфигурирования dwRc = DialogBox(hMod, "CONFIG", NULL, DlgProc); break; } // Все необработанные сообщения необходимо // передать функции DefDriverProc default: { return DefDriverProc(dwDiverId, hDriver, msg, lParam1, lParam2); } } return dwRc; } // ====================================================== // Функция DldProc // Обработка сообщений диалоговой панели конфигурирования // ====================================================== #pragma argsused int CALLBACK _export DlgProc(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam) { static BOOL fWasActive, fChanged; switch(msg) { case WM_INITDIALOG: { // Определяем текущее состояние строки "Enable=" fWasActive = GetPrivateProfileInt(szDriverName, "Enable", 0, "system.ini"); // В соответствии с этим состоянием отмечаем // переключатель, управляющий возможностью запуска // приложений Windows из командной строки MS-DOS CheckDlgButton(hdlg, ID_ENABLE, fWasActive); return TRUE; } case WM_COMMAND: { switch(wParam) { case IDOK: { // Флаг изменения режима работы драйвера // при его конфигурировании fChanged = TRUE; // Если переключатель находится во включенном // состоянии, разрешаем работу драйвера if(IsDlgButtonChecked(hdlg, ID_ENABLE)) { if(fWasActive) fChanged = FALSE; // Заносим изменения в файл system.ini WritePrivateProfileString(szDriverName, "Enable", "1", "system.ini"); // Разрешаем автоматический запуск wast.exe AutoStartWAST(TRUE); } // Если переключатель находился в выключенном // состоянии, запрещаем работу драйвера else { if(!fWasActive) fChanged = FALSE; WritePrivateProfileString(szDriverName, "Enable", "0", "system.ini"); AutoStartWAST(FALSE); } // Если был изменен режим работы драйвера, // запрашиваем перезапуск Windows EndDialog(hdlg, fChanged ? DRVCNF_RESTART : DRVCNF_CANCEL); return TRUE; } // Отмена изменения конфигурации case IDCANCEL: { EndDialog(hdlg, DRVCNF_CANCEL); return TRUE; } } } } return FALSE; } // ====================================================== // Функция AutoStartWAST // В зависимости от значения параметра эта функция // дописывает имя приложения wast.exe в строке // "load=" раздела [windows] файла win.ini // или наоборот, удаляет имя wast.exe из этой строки // ====================================================== void AutoStartWAST(BOOL fStart) { static LPSTR lpszSubst; // Получаем строку "load=..." во временный буфер GetProfileString("windows", "load", "", szTemp, 80); // Ищем в этой строке имя приложения wast.exe lpszSubst = _fstrstr(szTemp, (LPSTR)"wast"); // Если параметр функции равен TRUE, добавляем // имя в строку if(fStart) { // Добавляем только в том случае, если этого // имени там нет if(lpszSubst == NULL) { lstrcat(szTemp, " "); lstrcat(szTemp, "wast"); } } // Если параметр функции равен FALSE, удаляем // имя приложения wast.exe из строки else { // Удаляем только в том случае, если это имя // там действительно есть if(lpszSubst != NULL) { _fstrcpy(lpszSubst, lpszSubst + _fstrlen(lpszSubst)); } } // Сохраняем новое значение строки "load=..." WriteProfileString("windows", "load", szTemp); } Функция LibMain загружаемого драйвера аналогична такой же функции DLL-библиотеки d2w.dll. Она получает и сохраняет точку входа виртуального драйвера и дополнительно запоминает в глобальной переменной идентификатор модуля загружаемого драйвера. Функция WEP отменяет регистрацию при выгрузке драйвера из памяти, вызывая функцию UnregisterTask. Эта функция полностью аналогична функции UnregisterWnd библиотеки d2w.dll, причину изменения названия вы узнаете чуть позже. Функция WinAppStart выполняет ту же задачу, что и одноименная функция из библиотеки d2w.dll, однако делает она это немного по-другому. Обратите внимание, что для посылки сообщения приложению wast.exe (аналогичного приложению dos2win.exe) мы использовали вместо функции PostMessage функцию PostAppMessage. Это связано с тем, что приложение wast.exe вообще не создает главного окна, хотя, тем не менее, имеет цикл обработки сообщений! (Разумеется, вы можете использовать и старый метод, использованный в приложении dos2win.exe). В качестве первого параметра функции PostAppMessage необходимо передать идентификатор задачи wast.exe (а не идентификатор окна, которое, кстати, вообще не существует). Идентификатор задачи сохраняется в глобальной переменной функцией RegisterTask, которая соответствует функции RegisterWnd библиотеки d2w.dll, но вызывается по-другому. Вызов этой функции выполняется из функции DriverProc при обработке пользовательского сообщения UDRV_REGISTERTASK, посылаемого загружаемому драйверу приложением wast.exe. Аналогично, обработчик другого пользовательского сообщения UDRV_UNREGISTERTASK вызывает функцию UnregisterTask, действие которой полностью аналогично действию функции UnregisterWnd библиотеки d2w.dll. Функция DriverProc обрабатывает все необходимые сообщения, реагируя на них соответствующим образом. Мы не будем повторять комментарии, приведенные в исходном тексте. Отметим только, что при установке загружаемого драйвера обработчик сообщения DRV_INSTALL дописывает имя приложения wast.exe в строке "load=" файла win.ini, обеспечивая автоматический запуск приложения wast.exe. Для этого он вызывает функцию AutoStartWAST с параметром TRUE. При удалении драйвера обработчик сообщения отменяет автоматический запуск wast.exe, вызывая функцию AutoStartWAST с параметром FALSE. Перед этим выполняется отмена регистрации. В добавок приложению wast.exe посылается пользовательское сообщение WM_UNLOADWAST. Получив это сообщение, приложение wast.exe завершает свою работу. Пользовательские сообщения для приложения wast.exe и для загружаемого драйвера, идентификатор виртуального драйвера, а также константа ID_ENABLE определены в файле wastdrv.hpp (листинг 5.13). Листинг 5.13. Файл wast\wastdrv.hpp #define WM_STARTWINAPP (WM_USER + 100) #define WM_UNLOADWAST (WM_USER + 101) #define UDRV_REGISTERTASK (DRV_USER - 10) #define UDRV_UNREGISTERTASK (DRV_USER - 11) #define VXD_ID 0x8000 #define ID_ENABLE 101 Номера процедур программного интерфейса виртуального драйвера, точка входа программного интерфейса и прототип функции для получения точки входа определены в файле wastvxd.hpp (листинг 5.14). Листинг 5.14. Файл wast\wastvxd.hpp #define vxdapiGetVersion 0 #define vxdapiRegisterTask 1 #define vxdapiUnregisterTask 2 typedef unsigned long (far *VXDAPI)(void); VXDAPI vxdGetDeviceAPI(unsigned short vxd_id); Файл ресурсов загружаемого драйвера (листинг 5.15) содержит определение пиктограммы и диалоговой панели конфигурирования драйвера. Листинг 5.15. Файл wast\wastdrv.rc #include "wastdrv.hpp" AppIcon ICON "wast.ico" CONFIG DIALOG 11, 18, 167, 139 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Configure Driver WASTDRV" BEGIN ICON "APPICON", -1, 4, 7, 16, 16, WS_CHILD | WS_VISIBLE DEFPUSHBUTTON "OK", IDOK, 43, 118, 33, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP LTEXT "Version 1.0", -1, 30, 18, 120, 9, WS_CHILD | WS_VISIBLE | WS_GROUP CONTROL "", -1, "static", SS_BLACKRECT | WS_CHILD | WS_VISIBLE, 31, 36, 129, 1 LTEXT "Copyright © 1995 Alexandr Frolov" "\n\nfrolov@glas.apc.org", -1, 30, 41, 114, 28, WS_CHILD | WS_VISIBLE | WS_GROUP CONTROL "", -1, "static", SS_BLACKRECT | WS_CHILD | WS_VISIBLE, 31, 74, 129, 1 LTEXT "Installable Driver WASTDRV", -1, 30, 6, 108, 12, WS_CHILD | WS_VISIBLE | WS_GROUP CONTROL "", ID_ENABLE, "BUTTON", BS_AUTOCHECKBOX | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 31, 87, 10, 15 LTEXT "Enable Starting Windows Application from MS-DOS Command Prompt", -1, 43, 90, 124, 18, WS_CHILD | WS_VISIBLE | WS_GROUP PUSHBUTTON "Cancel", IDCANCEL, 91, 118, 32, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP END Файл определения модуля загружаемого драйвера практически ничем не отличается от аналогичного файла для DLL-библиотеки d2w.dll: Листинг 5.16. Файл wast\wastdrv.def LIBRARY WASTDRV DESCRIPTION 'Driver WASTDRV, (C) 1995, Frolov A.V.' EXETYPE windows CODE preload fixed DATA preload fixed single HEAPSIZE 1024 Для обеспечения возможности автоматической установки комплекса, состоящего из загружаемого драйвера wastdrv.dll, виртуального драйвера vxdsrv.386 и приложения wast.exe дистрибутивная дискета должна содержать помимо перечисленных файлов файл с именем oemsetup.inf (листинг 5.17). Листинг 5.17. Файл wast\oemsetup.inf [disks] 1 = ., "WAST Installable Driver Disk 1" [Installable.Drivers] wastdrvr=1:wastdrv.dll,"WAST", "WAST Installable Driver","1:vxdsrv.386", [wastdrvr] 1:wast.exe Секция [disks] этого файла описывает дистрибутивные дискеты. В нашем случае дистрибутив системы WAST состоит из одной дискеты с номером 1. Диск называется "WAST Installable Driver Disk 1". Именно эта строка появится в списке при установке драйвера приложением Control Panel. Секция [Installable.Drivers] описывает устанавливаемые драйверы. Мы устанавливаем драйвер wastdrvr, который расположен на первом диске дистрибутива. Имя соответствующего файла - wastdrv.dll. Тип драйвера, который появится в секции [drivers] файла system.ini, указан как WAST, поэтому в секцию [drivers] будет добавлена следующая строка: [drivers] WAST=wastdrv.dll В списке установленных драйверов, отображаемом приложением Control Panel, наш загружаемый драйвер будет показан с названием "WAST Installable Driver". В добавок, на первом диске дистрибутива имеется виртуальный драйвер vxdsrv.386, который поставляется вместе с загружаемым драйвером и должен автоматически копироваться в системный каталог Windows, а также автоматически подключаться в секции [386Enh] файла system.ini. В файле oemsetup.inf мы создали секцию [wastdrvr], в которой можно перечислить любые файлы, копируемые в системный каталог Windows в процессе установки. Мы копируем загрузочный модуль приложения wast.exe. Приложение WASTПриложение WAST (листинг 5.18) не создает главного окна и не знает ничего о виртуальном драйвере vxdsrv.386, хотя обращается к нему косвенно через загружаемый драйвер wastdrv.dll. Листинг 5.18. Файл wast\wast.cpp // ====================================================== // Приложение WAST // ------------------------------------------------------ // Запуск приложений Windows из // командной строки MS-DOS // // Используется совместно с загружаемым драйвером // wastdrv.dll и VxD-драйвером VXDSRV.386 версии 1.1. // Запускается автоматически при загрузке Windows. // Автоматический запуск можно отменить, изменив // конфигурацию драйвера WASTDRVR при помощи приложения // Control Panel // ------------------------------------------------------ // Copyright (C) 1995 Александр Фролов, Сергей Ноженко // ====================================================== #define STRICT #include <windows.h> #include <dir.h> #include "wast.hpp" BOOL InitApp(HINSTANCE); static char szDriverName[] = "wastdrv.dll"; struct LOADPARMS { WORD segEnv; // среда LPSTR lpszCmdLine; // коммандная строка LPWORD lpwShow; // режим отображения LPWORD lpwReserved; // зарезервировано }; struct LOADPARMS parms; WORD awShow[2] = { 2, SW_SHOW }; LPSTR lpszCmd, lpszParm; char szCurPath[128]; char szBuf[256]; // char szTempBuf[256]; // ====================================================== // Функция WinMain // ====================================================== #pragma argsused int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow) { if(hPrevInstance) // только одна копия приложения return FALSE; // Открываем драйвер HDRVR hDriver = OpenDriver(szDriverName, NULL, NULL); HTASK hTask; if(hDriver) { // Получаем идентификатор текущей задачи hTask = GetCurrentTask(); // Регистрируем в драйвере текущую задачу BOOL rc = (BOOL)SendDriverMessage( hDriver, UDRV_REGISTERTASK, (LPARAM)hTask, NULL); // Если не удалось зарегистрировать задачу, // виртуальный драйвер vxdsrv.386 не загружен if(!rc) { MessageBox(NULL, "Error Loading WAST\n" "Driver vxdsrv.386 not found", "Windows Application Starter", MB_OK | MB_ICONHAND); return FALSE; } } // Если не удалось открыть загружаемый драйвер, // выводим сообщение об ошибке else { MessageBox(NULL, "Error Loading WAST\n" "Driver wastdrv.dll not found", "Windows Application Starter", MB_OK | MB_ICONHAND); return FALSE; } MSG msg; while(GetMessage(&msg, NULL, 0, 0)) { // Это сообщение посылается загружаемым драйвером // wastdrv.dll, когда VxD-драйвер фиксирует запуск // программы любой виртуальной машиной MS-DOS if (msg.message == WM_STARTWINAPP) { // Создаем и активируем временное невидимое окно, // переключая системную виртуальную машину из фонового // режима в основной режим HWND hDummyWnd = CreateWindow("static", "", WS_POPUP, 0, 0, 0, 0, HWND_DESKTOP, NULL, hInstance, NULL); ShowWindow(hDummyWnd, SW_SHOW); DestroyWindow(hDummyWnd); // Адрес командной строки lpszCmd = (LPSTR)msg.lParam + 65; // Адрес строки параметров lpszParm = (LPSTR)msg.lParam + 65 + 128; // Устанавливаем текущий каталог setdisk(*LPSTR(msg.lParam)); szBuf[0] = *LPSTR(msg.lParam) + 'A'; szBuf[1] = ':'; szBuf[2] = '\\'; lstrcpy(szBuf + 3, LPSTR(msg.lParam) + 1); chdir(szBuf); // Готовим параметры для LoadModule lstrcpy(szBuf, (LPCSTR)" "); lstrcat(szBuf, (LPCSTR)lpszParm); *szBuf = (BYTE)lstrlen(lpszParm); if(lstrlen(lpszParm) != 0) parms.lpszCmdLine = (LPSTR)szBuf; else parms.lpszCmdLine = (LPSTR)""; parms.segEnv = 0; parms.lpwShow = (LPWORD) awShow; parms.lpwReserved = (LPWORD) NULL; // Копируем командную строку и параметры // lstrcpy(szTempBuf, (LPSTR)msg.lParam + 65); // lstrcat(szTempBuf, (LPSTR)msg.lParam + 65 + 128); // Запускаем приложение Windows LoadModule(lpszCmd, &parms); // WinExec(szTempBuf, SW_SHOW); } // Это сообщение поступает от загружаемого драйвера // при его удалении, выполняемом из приложения // Control Panel else if (msg.message == WM_UNLOADWAST) PostQuitMessage(0); else DispatchMessage(&msg); } // Отменяем регистрацию текущей задачи SendDriverMessage(hDriver, UDRV_UNREGISTERTASK, (LPARAM)hTask, NULL); // Закрываем драйвер CloseDriver(hDriver, NULL, NULL); return msg.wParam; } Первое, что делает функция WinMain - открывает загружаемый драйвер, вызывая для этого функцию OpenDriver. Затем приложение получает идентификатор текущей задачи (т. е. свой идентификатор задачи), и регистрирует его в загружаемом драйвере, посылая тому сообщение UDRV_REGISTERTASK. Далее запускается цикл обработки сообщений. При обработке сообщения WM_STARTWINAPP выполняется запуск приложения Windows. Для быстрого переключения системной виртуальной машины из фонового режима в основной мы создаем окно с нулевыми размерами, а затем сразу же отображаем и удаляем его. После этого запускаем приложение функцией LoadModule. Вы можете также попробовать использовать для запуска функцию WinExec, для чего следует переставить соответствующим образом символы комментария. При поступлении в очередь сообщения WM_UNLOADWAST работа приложения wast.exe завершается. Напомним, что это сообщение посылается приложению при удалении загружаемого драйвера. Перед завершением своей работы приложение wast.exe отменяет регистрацию и закрывает загружаемый драйвер. Все пользовательские сообщения определены в файле wast.hpp (листинг 5.19). Листинг 5.19. Файл wast\wast.hpp #define WM_STARTWINAPP (WM_USER + 100) #define WM_UNLOADWAST (WM_USER + 101) #define UDRV_REGISTERTASK (DRV_USER - 10) #define UDRV_UNREGISTERTASK (DRV_USER - 11) Файл ресурсов приведен в листинге 5.20. Листинг 5.20. Файл wast\wast.rc #include "wast.hpp" AppIcon ICON "wast.ico" Файл описания модуля для приложения wast.exe вы сможете найти в листинге 5.21. Листинг 5.21. Файл wast\wast.def NAME WAST DESCRIPTION 'WAST: Windows App Starter, (C) 1995, Frolov A.V.' EXETYPE windows STUB 'winstub.exe' STACKSIZE 8120 HEAPSIZE 1024 CODE preload moveable discardable DATA preload moveable multiple |