Операционная система Microsoft Windows 3.1 для программиста© Александр Фролов, Григорий ФроловТом 11 М.: Диалог-МИФИ, 1993, 269 стр. 8.5. Интерфейс EasyWinПосмотрите на исходный текст приложения Windows, приведенный в листинге 8.1. Не торопитесь делать вывод, что эта программа попала сюда случайно из учебника по языку программирования Си Кернигана и Риччи. То, что вы видите, и в самом деле приложение Windows. Вы можете легко в этом убедиться, если запустите exe-файл этого приложения, который есть на дискете (дискета продается вместе с книгой). Главное окно приложения изображено на рис. 8.2. Листинг 8.1. Файл easywin\easywin1.cpp #include <stdio.h> int main(void) { printf("Hello, world!"); return 0; }
Рис. 8.2. Окно приложения EASYWIN1 Но есть одна маленькая тонкость. В проекте должно быть указано, что данная программа есть не что иное, как приложение Windows. Если вы не купили дискету, прилагаемую к книге, и набрали приведенный выше текст программы самостоятельно, выберите из меню "Options" среды Borland C++ for Windows строку "Application...". На экране появится диалоговая панель "Application Options" (рис. 8.3).
Рис. 8.3. Диалоговая панель "Application Options" В этой диалоговой панели вам надо нажать кнопку с надписью "Windows App". Когда вы собираете загрузочный модуль приложения, компилятор находит там вместо функции WinMain функцию main. Так как в проекте указано, что данное приложение является приложением Windows, компилятор автоматически подключает к приложению функции интерфейса EasyWin и оно становится приложением Windows. А как же, спросите вы, быть без функции WinMain? Очень просто - эта функция есть, она определена в подключаемых к вашему приложению функциях EasyWin. Фактически интерфейс EasyWin полностью скрывает от программиста интерфейс Windows, предоставляя ему взамен старый добрый интерфейс консольного ввода/вывода. В программах EasyWin вы можете пользоваться всеми стандартными функциями ввода/вывода, такими, как printf, gets, getch и т. д. Дополнительно можно вызывать функции gotoxy, wherex, wherey, clrscr и clreol, которые входят в стандартную библиотеку Borland C++ для MS-DOS. Аналогичный интерфейс предусмотрен и в системе разработки Microsoft Visual C++. Этот интерфейс называется QuickWin. Он позволяет использовать практически любые функции стандартной библиотеки транслятора для MS-DOS, в том числе графические. Создаваемое с помощью этого интерфейса приложение может работать в среде Windows в полноэкранном режиме, внешне не отличаясь от своего варианта для MS-DOS. Зачем все это нужно? Мы так долго говорили о преимуществах Windows, а теперь снова возвратились к MS-DOS? Возвратились, но не совсем. Мы можем использовать функции консольного ввода/вывода, но этот вывод выполняется не на экран реального видеомонитора, а в обычное окно Windows. Наше приложение работает в защищенном режиме и может использовать все преимущества адресации расширенной памяти, доступные стандартному приложению Windows. Кроме того, в приложении можно вызывать и обычные функции программного интерфейса Windows. Для чего же обычно используют интерфейс EasyWin? Во-первых, для переноса старых программ в среду Windows. Если у вас есть исходные тексты программ MS-DOS, составленных на языке программирования Си, которыми вы продолжаете пользоваться и которые для ввода/вывода на экран используют только функции консольного ввода/вывода, вы сможете без особого труда сделать из этих программ приложения Windows. Для этого вам достаточно перетранслировать их в среде Borland C++ for Windows версии 3.1, указав в проекте, что нужно сделать приложение Windows. Скорее всего вам не придется менять ни одной строчки исходного кода. Во-вторых, интерфейс EasyWin удобно использовать для создания небольших тестовых приложений, когда нужно быстро получить результат. В качестве примера такого приложения приведем второй вариант приложения TMETRICS, предназначенного для просмотра пространственных характеристик шрифта, выбранного в контекст отображения (листинг 8.2). Листинг 8.2. Файл easywin\easywin2.cpp #include <windows.h> #include <stdio.h> #include <conio.h> // Прототип функции void Print(int, char *); // ============================================== // Функция main // ============================================== int main(void) { HDC hdc; TEXTMETRIC tm; // структура для записи метрик шрифта printf("Нажмите любую клавишу..."); // Ожидаем ввода с клавиатуры любого символа getch(); printf("\nПараметры шрифта:\n" "-----------------\n"); // Создаем контекст отображения, // необходимый для определения метрик шрифта hdc = CreateDC("DISPLAY", NULL, NULL, NULL); // Заполняем структуру информацией // о метрике шрифта, выбранного в // контекст отображения GetTextMetrics(hdc, &tm); // Выводим параметры шрифта Print(tm.tmHeight, "tmHeight"); Print(tm.tmAscent, "tmAscent"); Print(tm.tmDescent, "tmDescent"); Print(tm.tmInternalLeading, "tmInternalLeading"); Print(tm.tmExternalLeading, "tmExternalLeading"); Print(tm.tmAveCharWidth, "tmAveCharWidth"); Print(tm.tmMaxCharWidth, "tmMaxCharWidth"); Print(tm.tmWeight, "tmWeight"); Print(tm.tmItalic, "tmItalic"); Print(tm.tmUnderlined, "tmUnderlined"); Print(tm.tmStruckOut, "tmStruckOut"); Print(tm.tmFirstChar, "tmFirstChar"); Print(tm.tmLastChar, "tmLastChar"); Print(tm.tmDefaultChar, "tmDefaultChar"); Print(tm.tmBreakChar, "tmBreakChar"); Print(tm.tmPitchAndFamily, "tmPitchAndFamily"); Print(tm.tmCharSet, "tmCharSet"); Print(tm.tmOverhang, "tmOverhang"); Print(tm.tmDigitizedAspectX,"tmDigitizedAspectX"); Print(tm.tmDigitizedAspectY,"tmDigitizedAspectY"); // Уничтожаем созданный нами контекст DeleteDC(hdc); // Выводим сообщение о завершении работы программы MessageBox(NULL,"Работа программы закончена, " "для просмотра результатов нажмите кнопку OK", "Демонстрация EASYWIN", MB_OK | MB_ICONINFORMATION); return 0; } // ========================================== // Функция для вывода параметров шрифта // в окно // ========================================== void Print(int tmValue, char *str) { printf("%-20s\t= %d\n", str, tmValue); } В этом приложении мы создаем контекст отображения, вызывая функцию программного интерфейса Windows CreateDC. Затем мы вызываем знакомую вам функцию GetTextMetrics, определяющую метрики шрифта. Названия метрик и соответствующие численные значения выводятся в окно приложения функцией Print. Функция Print определена в нашем приложении и выглядит чрезвычайно просто благодаря применению для вывода функции printf. Главное окно приложения изображено на рис. 8.4.
Рис. 8.4. Главное окно приложения EASYWIN2 Без малейших усилий с нашей стороны у окна появились вертикальная и горизонтальная полосы просмотра, с помощью которых можно увидеть целиком окно "виртуальной консоли". Обратите внимание также на то, что мы вызываем в этой программе функцию программного интерфейса MessageBox. А можно ли поступить наоборот - из обычного приложения Windows инициализировать интерфейс EasyWin и воспользоваться функциями консольного ввода/вывода? Можно, именно так мы и поступили в нашем следующем приложении, которое выполняет такие нетипичные для приложений задачи, как перезагрузка компьютера или перезапуск операционной системы Windows (листинг 8.3). Листинг 8.3. Файл easywin\easywin3.cpp #define STRICT #include <windows.h> #include <stdio.h> #include <conio.h> // =========================================== // Функция WinMain // =========================================== #pragma argsused int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow) { BYTE szBuf[128]; int cbBufSize; BYTE ch; // Инициализация интерфейса EasyWin _InitEasyWin(); // Получаем путь к каталогу, в котором // установлена Windows GetWindowsDirectory(szBuf, cbBufSize); printf("Каталог Windows: %s\n\n", szBuf); printf("Нажмите:\n\n" "R - перезапуск системы\n" "W - перезапуск Windows\n" "N - запуск Norton Commander и возврат в Windows\n\n" "или любую другую клавишу ->\n" ); ch = getch(); if(ch == 'R' || ch == 'r') { // Перезагрузка компьютера if(!ExitWindows(EW_REBOOTSYSTEM, 0)) { printf("Ошибка при завершении работы Windows"); } } else if(ch == 'W' || ch == 'w') { // Перезапуск Windows if(!ExitWindows(EW_RESTARTWINDOWS, 0)) { printf("Ошибка при завершении работы Windows"); } } else if(ch == 'N' || ch == 'n') { // Временное завершение работы Windows, // запуск программы MS-DOS, затем // снова запуск Windows if(!ExitWindowsExec("g:\\nc\\nc.exe", NULL)) { printf("Ошибка при завершении работы Windows"); } } return 0; } Это приложение содержит стандартную для Windows функцию WinMain. Для инициализации интерфейса EasyWin вызывается функция _InitEasyWin, описанная в файлах stdio.h, io.h, iostream.h: void _Cdecl _InitEasyWin(void); После вызова этой функции появляется окно и вы можете вызывать стандартные функции консольного ввода/вывода. В качестве примера мы вызываем функцию GetWindowsDirectory, которая возвращает полный путь к каталогу, содержащему файлы операционной системы Windows: UINT WINAPI GetWindowsDirectory(LPSTR lpszSysPath, UINT cbSysPath); Параметр lpszSysPath является указателем на буфер, в который будет записан путь к каталогу Windows. Длина буфера должна быть не менее 144 символов, она задается параметром cbSysPath. Функция GetWindowsDirectory возвращает длину строки записанной в буфер, без учета закрывающего строку двоичного нуля. Если вы не предусмотрели буфер достаточного размера, функция возвратит требуемый размер буфера. В случае ошибки возвращается нулевое значение. Получив строку пути к каталогу Windows, приложение отображает его на экране и предлагает меню (рис. 8.5).
Рис. 8.5. Главное окно приложения EASYWIN3 В этом меню вам предлагается три возможности. Нажав клавишу <R>, вы сможете завершить работу Windows и перезагрузить компьютер. При этом будет выполнена загрузка MS-DOS. Если вы нажмете клавишу <W>, произойдет перезапуск Windows без перезагрузки компьютера. Если нажать клавишу <N>, работа Windows будет завершена и запустится Norton Commander (если он есть на диске вашего компьютера). После завершения работы программы Norton Commander произойдет автоматический запуск Windows. Для перезапуска Windows и перезагрузки компьютера мы использовали функцию программного интерфейса Windows с именем ExitWindows: BOOL WINAPI ExitWindows(DWORD dwReturnCode, UINT wReserved); Старший байт параметра dwReturnCode должен быть равен нулю, младший байт должен содержать код возврата, передаваемый MS-DOS при завершении работы Windows:
Параметр wReserved зарезервирован и должен быть равен нулю. Функция ExitWindowsExec определена в программном интерфейсе Windows версии 3.1. Она завершает работу Windows, передавая управление указанной в параметре программе MS-DOS. После завершения работы этой программы Windows запускается вновь. Приведем прототип функции ExitWindowsExec: BOOL WINAPI ExitWindowsExec(LPCSTR lpszExe, LPCSTR lpszParams); Параметр lpszExe является дальним указателем на строку символов, закрытую двоичным нулем, содержащую путь к запускаемой программе MS-DOS. Через параметр lpszParams запускаемой программе можно передать строку параметров. Это значение можно задать как NULL. При невозможности завершить работу Windows или в случае появления других ошибок функция возвращает значение FALSE. Как правило, функции ExitWindowsExec и ExitWindows используются в программах установки программного обеспечения для Windows (в инсталляторах). О том, как создавать собственные инсталляторы, мы расскажем в отдельной главе в одной из следующих книг серии "Библиотека системного программиста". |