Операционная система Microsoft Windows 3.1 для программиста. Дополнительные главы

Файл dos2win\d2w.cpp


// ====================================================== // 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));
}

В фиксированном сегменте данных библиотеки d2w.dll хранится идентификатор главного окна приложения dos2win.exe (переменная hwndDos2Win), который используется для посылки этому приложению сообщения WM_STARTWINAPP.

Кроме этого, в этом сегменте располагается буфер szCallbackBuf, адрес которого передается виртуальному драйверу при регистрации. Именно в этот буфер виртуальный драйвер записывает строку параметров, "подсмотренную" у функции прерывания INT21h, запускающей программы MS-DOS.

При начальной загрузке DLL-библиотеки в память функция LibMain получает адрес точки входа программного интерфейса виртуального драйвера VXDSRV, вызывая для этого функцию vxdGetDeviceAPI.

Напомним, что в процессе создания своего главного окна приложение dos2win.exe вызывает функцию RegisterWnd, определенную в библиотеке d2w.dll. Эта функция не только сохраняет полученный ей через параметр идентификатор главного окна, но и вызывает функцию регистрации vxdapiRegisterWnd из программного интерфейса драйвера VXDSRV.

В регистрах DX:CX функции регистрации драйвера передается адрес функции обратного вызова WinAppStart, определенной в DLL-библиотеке, а через регистры SI:DI - адрес буфера szCallbackBuf, в который драйвер будет записывать параметры запускаемого приложения Windows.

Функция WEP, которая вызывается при удалении DLL-библиотеки из памяти, вызывает функцию отмены регистрации UnregisterWnd, определенную в библиотеке d2w.dll. Задача функции UnregisterWnd заключается в простом вызове функции vxdapiUnregisterWnd из программного интерфейса виртуального драйвера.

Так как библиотека d2w.dll будет выгружена из памяти при завершении работы загрузившего ее приложения dos2win.exe, произойдет автоматическая отмена регистрации. Это означает, что после завершения dos2win.exe виртуальный драйвер VXDSRV будет отключен и, следовательно, запуск приложений Windows из командной строки виртуальной машины MS-DOS будет невозможен. Разумеется, до следующего запуска dos2win.exe!



Функция обратного вызова WinAppStart вызывается виртуальным драйвером.

Прежде всего, функция проверяет версию драйвера, которая передается ей в качестве параметра. Конечно, версию драйвера лучше было бы определить с помощью специально предназначенной для этого функции программного интерфейса драйвера, но мы использовали этот способ для иллюстрации возможности передачи параметров из виртуального драйвера.

На момент вызова функции WinAppStart буфер szCallbackBuf содержит строку параметров запускаемого приложения. Эта строка записывается в очередь, организованную в виде кольца на базе массива szCmd.

Вслед за этим в очередь сообщений главного окна приложения dos2win.exe посылается сообщение WM_STARTWINAPP. Это можно сделать только функцией PostMessage (или PostAppMessage), так как только эти функции допускают реентерабельный вызов.

Почему используется очередь?

Дело в том, что пользователь может запустить пакетный bat-файл, содержащий вызовы приложений Windows (да, теперь возможен и такой симбиоз между старой технологией запуска программ MS-DOS и приложениями новейшей операционной системы Windows). В этом случае функция WinAppStart будет вызываться очень часто, поэтому буфер szCallbackBuf будет перезаписываться новой информацией еще до завершения обработки старой.

Сообщение WM_STARTWINAPP и идентификатор виртуального драйвера определены в файле d2w.h (листинг 5.10).


Содержание раздела