Операционная система Microsoft Windows 3.1 для программиста -том 1

   Купить лепнину Карниз Гладкий Кг-01 058, inf. |       

Интерфейс 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:

Параметр Описание
EW_RESTARTWINDOWS Перезапуск Windows
EW_REBOOTSYSTEM Завершение работы Windows и перезапуск системы. Этот код допустим только для Windows версии 3.1 и более старших версий
Параметр 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 (в инсталляторах). О том, как создавать собственные инсталляторы, мы расскажем в отдельной главе в одной из следующих книг серии "Библиотека системного программиста".


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