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

         

Файл dos2win\dos2win.cpp


// ====================================================== // Приложение DOS2WIN // // Запуск приложений Windows из // коммандной строки MS-DOS // // Используется совместно с DLL-библиотекой // d2w.dll и VxD-драйвером VXDSRV.386 версии 1.1 // ------------------------------------------------------ // Copyright (C) 1995 Alexandr Frolov // ====================================================== #define STRICT #include <windows.h>
#include <mem.h>
#include <string.h>
#include <dir.h>

#include "dos2win.hpp" #include "vxdcall.hpp"

BOOL InitApp(HINSTANCE);

LRESULT CALLBACK _export WndProc(HWND, UINT, WPARAM, LPARAM);

extern "C" void FAR PASCAL _export WinAppStart(HWND hwnd, LPSTR szPath);

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

BOOL CALLBACK _export DlgProc(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam);

char const szClassName[] = "DOS2WINClass"; char const szWindowTitle[] = "dos2win"; HINSTANCE hInst; HMENU hmenuSystemMenu;

struct LOADPARMS { WORD segEnv; // среда LPSTR lpszCmdLine; // коммандная строка LPWORD lpwShow; // режим отображения LPWORD lpwReserved; // зарезервировано }; struct LOADPARMS parms;

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

WORD awShow[2] = { 2, SW_SHOW }; LPSTR lpszCmd, lpszParm; char szBuf[256]; char szCurPath[128];

DLGPROC lpfnDlgProc;

// ====================================================== // Функция WinMain // ====================================================== #pragma argsused int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow) { MSG msg; HWND hwnd;

if(hPrevInstance) // только одна копия приложения return FALSE;

if(!InitApp(hInstance)) return FALSE;

hInst = hInstance;

hwnd = CreateWindow( szClassName, szWindowTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, hInstance, NULL);

if(!hwnd) return FALSE;

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




// Если VxD-драйвер не загружен, выводим // сообщение об ошибке if(vxd == NULL) { MessageBox(hwnd, "Error Loading DOS2WIN\n" "VxD Driver VXDSRV.386 not found", "DOS2WIN", MB_OK | MB_ICONHAND);
return FALSE; }

// Отображаем окно в виде пиктограммы ShowWindow(hwnd, SW_SHOWMINIMIZED);
UpdateWindow(hwnd);

while(GetMessage(&msg, 0, 0, 0)) { TranslateMessage(&msg);
DispatchMessage(&msg);
} return msg.wParam; }

// ====================================================== // Функция InitApp // Выполняет регистрацию класса окна // ====================================================== BOOL InitApp(HINSTANCE hInstance) { ATOM aWndClass; WNDCLASS wc;

memset(&wc, 0, sizeof(wc));
wc.lpszMenuName = "APP_MENU"; wc.style = 0; wc.lpfnWndProc = (WNDPROC) WndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = LoadIcon(hInstance, "AppIcon");
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszClassName = (LPSTR)szClassName;

aWndClass = RegisterClass(&wc);
return (aWndClass != 0);
}

// ====================================================== // Функция WndProc // ====================================================== LRESULT CALLBACK _export WndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { case WM_CREATE: { // Регистрируем окно приложения в DLL-библиотеке d2w.dll RegisterWnd(hwnd);

// Изменяем системное меню приложения hmenuSystemMenu = GetSystemMenu(hwnd, FALSE);

AppendMenu(hmenuSystemMenu, MF_SEPARATOR, 0, 0);
AppendMenu(hmenuSystemMenu, MF_BYCOMMAND | MF_ENABLED, CM_SYSABOUT, "&About...");

return 0; }

// Удаляем лишние строки из системного меню приложения case WM_INITMENUPOPUP: { RemoveMenu(hmenuSystemMenu, SC_RESTORE, MF_BYCOMMAND);
RemoveMenu(hmenuSystemMenu, SC_MAXIMIZE, MF_BYCOMMAND);
RemoveMenu(hmenuSystemMenu, SC_MINIMIZE, MF_BYCOMMAND);
RemoveMenu(hmenuSystemMenu, SC_SIZE, MF_BYCOMMAND);
break; }



case WM_SYSCOMMAND: { switch(wParam & 0xfff0) { // Блокируем изменение размеров окна case SC_RESTORE: case SC_MAXIMIZE: case SC_SIZE: return 0;

// Выводим диалоговую панель "About" case CM_SYSABOUT: { lpfnDlgProc = (DLGPROC)MakeProcInstance((FARPROC)DlgProc, hInst);
DialogBox(hInst, "ABOUT", hwnd, lpfnDlgProc);
FreeProcInstance((FARPROC)lpfnDlgProc);
return 0; }

default: return DefWindowProc(hwnd, msg, wParam, lParam);
} }

// Это сообщение посылается DLL-библиотекой d2w.dll, // когда VxD-драйвер фиксирует запуск программы любой // виртуальной машиной MS-DOS. // Параметр lParam содержит указатель на строку, // имеющую следующий формат: // // Смещение Размер Описание // 0 1 Номер дискового устройства, которое // было текущим при запуске программы // 1 64 Каталог, который был текущим // при запуске программы // 65 128 Путь к запускаемой программе MS-DOS // или к запускаемому приложению Windows // 193 128 параметры запускаемой программы // или приложения //

case WM_STARTWINAPP: { // Проверка указателя if(lParam == NULL) return 0;

// Путь к запускаемой программе lpszCmd = (LPSTR)lParam + 65;

// Указатель на строку параметров lpszParm = (LPSTR)lParam + 65 + 128;

// Формируем буфер параметров для функции LoadModule // Первый байт резервируем для размера строки lstrcpy(szBuf, (LPCSTR)" ");
lstrcat(szBuf, (LPCSTR)lpszParm);

// Записываем размер строки *szBuf = (BYTE)lstrlen(lpszParm);

// Заполняем структуру LOADPARMS if(lstrlen(lpszParm) != 0) parms.lpszCmdLine = (LPSTR)szBuf; else parms.lpszCmdLine = (LPSTR)"";

parms.segEnv = 0; parms.lpwShow = (LPWORD) awShow; parms.lpwReserved = (LPWORD) NULL;

// Устанавливаем такой же текущий диск, // какой был текущим при запуске программы // из виртуальной машины MS-DOS setdisk(*(LPSTR)lParam);

// Устанавливаем такой же текущий каталог, // какой был текущим при запуске программы // из виртуальной машины MS-DOS szCurPath[0] = (char)((*(LPSTR)lParam) + 'A');
lstrcpyn((LPSTR)szCurPath + 1, (LPSTR)":\\", 3);
lstrcat((LPSTR)szCurPath, (LPSTR)lParam + 1);
chdir(szCurPath);



// Выполняем попытку запуска программы. // Если запускается приложение Windows, оно // будет запущено. Если же был выполнен запуск // программы MS-DOS, функция LoadModule вернет // код ошибки, который мы игнорируем LoadModule(lpszCmd, &parms);
return 0; }

case WM_DESTROY: { PostQuitMessage(0);
return 0; } default: break; } return DefWindowProc(hwnd, msg, wParam, lParam);
}

// ====================================================== // Функция 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));
}

// ====================================================== // Функция DldProc // Обработка сообщений диалоговой панели "About" // ====================================================== #pragma argsused

BOOL CALLBACK _export DlgProc(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam) { switch(msg) { case WM_INITDIALOG: return TRUE;

case WM_COMMAND: { switch(wParam) { case IDOK: case IDCANCEL: { EndDialog(hdlg, 0);
return TRUE; } } } } return FALSE; }

В этом приложении нет ничего особенного, за исключением того, что его окно всегда отображается в виде пиктограммы.

На этапе инициализации приложение определяет точку входа виртуального драйвера VXDSRV и отказывается работать, если этот драйвер не загружен.

Во время обработки сообщения WM_CREATE приложение вызывает функцию RegisterWnd, которая находится в DLL-библиотеке d2w.dll. В качестве единственного параметра функции передается идентификатор главного окна приложения, необходимый для передачи приложению сообщения WM_STARTWINAPP.

Вместе с сообщением WM_STARTWINAPP через параметр lParam передается адрес буфера, содержащего всю информацию, необходимую для запуска приложения Windows.Исходный текст обработчика сообщения содержит описание формата буфера.

Обработчик сообщения WM_STARTWINAPP формирует командную строку и структуру параметров, необходимую для вызова функции LoadModule, с помощью которой выполняется запуск приложения.

Непосредственно перед запуском приложение DOS2WIN изменяет текущий диск и каталог в соответствии со значениями, переданными в первых двух полях буфера.

Файл dos2win.hpp содержит определение сообщения WM_STARTWINAPP, констант CM_SYSABOUT и VXD_ID (листинг 5.5).


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