Электронная библиотека книг Александра Фролова и Григория Фролова.
Shop2You.ru Создайте свой интернет-магазин
Библиотека
Братьев
Фроловых

Операционная система 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

[Назад] [Содеожание] [Дальше]