// ======================================================
// DLL-библиотека d2w.dll
//
// Используется совместно с приложением dos2win.exe
// и VxD-драйвером VXDSRV.386 версии 1.1
// ------------------------------------------------------
// Copyright (C) 1995 Alexandr Frolov
// ======================================================
#define  STRICT
#include <windows.h>
#include <mem.h>
#include "d2w.h"
#include "vxdcall.hpp"

extern "C" void FAR PASCAL _export
WinAppStart(WORD wVxDVersion);

extern "C" void FAR PASCAL _export
RegisterWnd(HWND hwnd);

void UnregisterWnd(VXDAPI vxdEntry);

// Точка входа API VxD-драйвера
VXDAPI vxdApi = NULL;

// Идентификатор окна приложения dos2win.exe
HWND hwndDos2Win;

// В этот буфер VXD-драйвер VXDSRV.386 будет записывать
// текущий диск, текущий каталог, путь к запускаемой
// программе и параметры, использованные виртуальной
// машиной MS-DOS в процессе запуска программы
BYTE szCallbackBuf[350];

// Очередь запросов на запуск программ из VM MS-DOS
// Организована в виде массива
BYTE szCmd[6][350];

// Номер строки параметров в массиве szCmd
int nCmdLine = 0;

// ========================================================
// Функция LibMain
// Получает управление только один раз при
// загрузке DLL-библиотеки в память
// ========================================================
#pragma argsused
int FAR PASCAL
LibMain(HINSTANCE hModule, WORD wDataSegment,
  WORD wHeapSize, LPSTR lpszCmdLine)
{
  if(wHeapSize != 0)
    UnlockData(0);

  // Получаем точку входа API VxD-драйвера
  vxdApi = vxdGetDeviceAPI(VXD_ID);

  return TRUE;
}

// ========================================================
// Функция WEP
// ========================================================
#pragma argsused
int FAR PASCAL WEP(int bSystemExit)
{
  // Если DLL-библиотека выгружается из памяти,
  // выполняем отключение VxD-драйвера
  if(vxdApi != NULL)
    UnregisterWnd(vxdApi);
  return 1;
}

// ========================================================
// Функция обратного вызова WinAppStart
// Вызывается из VxD-драйвера VXDSRV.386
// Копирует строку, содержащую все характеристики
// запускаемой программы в очередь запросов, затем
// посылает сообщение WM_STARTWINAPP в приложение
// dos2win.exe, которое выполняет запуск.
// ========================================================
extern "C" void FAR PASCAL _export
WinAppStart(WORD wVxDVersion)
{
  // Проверяем версию VxD-драйвера, передаваемую
  // через параметр wVxDVersion
  if(wVxDVersion != 0x0101) return;

  // Копируем текущий каталог, путь к запускаемой
  // программе и ее параметры
  _fmemcpy((LPVOID)szCmd[nCmdLine], (LPVOID)szCallbackBuf, 65 + 256);

  // Посылаем сообщение приложению dos2win
  PostMessage(hwndDos2Win, WM_STARTWINAPP,
    0, (LPARAM)szCmd[nCmdLine]);

  // Очередь запросов организована в виде кольца
  nCmdLine++;
  if(nCmdLine > 5) nCmdLine = 0;
}

// ========================================================
// Функция RegisterWnd
// Регистрация окна приложения dos2win.exe
// ========================================================
extern "C" void FAR PASCAL _export
RegisterWnd(HWND hwnd)
{
  if(vxdApi == NULL) return;

  // Сохраняем идентификатор окна
  hwndDos2Win = hwnd;
  if(vxdApi == NULL) return;

  // Вычисляем компоненты адреса функции обратного вызова
  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, vxdapiRegisterWnd
  (*vxdApi)();
}

// ========================================================
// Функция UnregisterWnd
// Отключение VxD-драйвера
// ========================================================
void UnregisterWnd(VXDAPI vxdEntry)
{
  if(vxdApi == NULL) return;

  asm mov ax, vxdapiUnregisterWnd
  (*vxdEntry)();
}

// ========================================================
// Функция vxdGetDeviceAPI
// Получение адреса точки входа API для
// VxD-драйвера, идентификатор которого
// задан параметром vxd_id
// ========================================================
VXDAPI vxdGetDeviceAPI(unsigned short vxd_id)
{
  unsigned axreg, dxreg;

  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 pop   di

  asm mov   axreg, ax
  asm mov   dxreg, dx

  return((VXDAPI)MAKELP(dxreg, axreg));
}
