// ======================================================
// Загружаемый драйвер 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);
}
