8.1. Файл windows.h
8.2. Типы данных
8.3. Модели памяти
8.4. Использование символов кириллицы
8.5. Интерфейс EasyWin
8.6. Отладка приложений Windows
Исходные тексты любого приложения Windows включают файл windows.h:
#include <windows.h>
Этот файл содержит множество определений типов данных, макросов,
прототипов функций, констант и т. д.
Наряду с этим файлом вы можете включить в приложения и другие,
знакомые вам по MS-DOS, include-файлы, такие, как stdlib.h и string.h.
Если в проекте Borland C++ for Windows версии 3.1 указывается,
что создается приложение Windows, компилятор определяет символ
_WINDOWS. Этот символ влияет на включаемые файлы стандартной библиотеки
Си. В частности, из include-файлов могут быть исключены прототипы
функций, не совместимых с Windows.
Перед включением файла windows.h для выполнения более строгой
проверки типов рекомендуется определить символ STRICT:
#define STRICT
После включения этой строки многие типы данных определяются по-другому.
В частности, все многочисленные идентификаторы ресурсов Windows,
такие, как идентификатор контекста, идентификатор окна и т. п.,
определяются как различные типы данных. При этом вы не сможете
по ошибке выполнить, например, присваивание идентификатора окна
переменной, предназначенной для хранения идентификатора контекста
отображения или идентификатора меню.
Есть целый набор символов, при определении которых из файла windows.h
будут исключены определения функций или типов данных, связанных
с отдельными подсистемами Windows. Вы можете определить эти символы
для ускорения обработки файла windows.h при трансляции (разумеется,
если соответствующие подсистемы не используются вашим приложением).
Приведем список некоторых из таких символов.
Символ | Что исключает |
NOATOM | Прототипы функций для работы с атомами
|
NOCLIPBOARD | Прототипы функций, идентификаторы сообщений и константы для работы с универсальным буфером обмена Clipboard
|
NOCOMM | Прототипы функций, структуры и константы для работы с портом последовательной передачи данных
|
NOCTLMGR | Прототипы функций для работы с диалоговыми панелями, структуры и константы для работы с диалоговыми панелями, сообщения WM_CTLCOLOR, WM_GETFONT, WM_SETFONT, стили органов управления
|
NOCOLOR | Прототипы функций GetSysColor, SetSysColor и константы с префиксом COLOR
|
NODRAWTEXT | Прототип функции DrawText и связанные с этой функцией константы
|
NOGDI | Все определения функций и констант для графического интерфейса GDI
|
NOHELP | Функцию WinHelp, структуры и константы для нее
|
NOICONS | Идентификаторы встроенных пиктограмм
|
NOKERNEL | Прототип функции WinMain, определения всех функций ядра Windows, структур данных и константы
|
NOMB | Прототип функций MessageBox, MessageBeep и константы для них
|
NOMENUS | Прототипы функций и константы для работы с меню
|
NOMETAFILE | Прототипы функций и константы для работы с метафайлами
|
NOSYSCOMMANDS | Константы системных команд с префиксом SC
|
NOUSER | Прототипы и определения констант для пользовательских функций (эти функции относятся к программному интерфейсу Windows и вызываются приложениями)
|
NOVIRTUALKEYCODES | Коды виртуальных клавиш
|
NOWINMESSAGES | Определения кодов сообщений Windows
|
NOWINSTYLES | Константы для определения стилей окон
|
Для разработки приложений Windows используется большое количество
типов данных и констант, определенных в таких файлах, как windows.h,
commdlg.h и других. Эти типы данных как бы замещают собой стандартные
типы данных языка Си.
Такая замена позволяет отделить программный интерфейс Windows
от самой операционной системы Windows, с одной стороны, и от конкретных
реализаций компиляторов языка Си, с другой. Например, система
разработки программ Borland C++ версии 3.1 трактует тип unsigned int
как беззнаковое целое размером 16 бит. В файле windows.h определен
тип UNIT, который для указанной выше системы разработки отображается
на тип unsigned int :
typedef unsigned int UINT;
Однако при разработке 32-разрядных приложений (таких, как Windows
NT) для 32-разрядных процессоров тип UINT должен иметь размер
32 бит. Если вы будете думать о типе UINT как о типе, который
используется для представления беззнакового целого естественной
для данного процессора длины, вы можете избежать ошибок, связанных
с неправильным определением размера целого числа без знака.
Другой пример - дальний указатель на строку символов char _far *.
Для разработки приложений Windows версии 3.1 в среде разработки
Borland C++ вместо этого типа данных используется тип LPSTR, определенный
следующим образом:
typedef char FAR* LPSTR;
Ключевое слово FAR определено так:
#define FAR _far
В 16-разрядной среде тип LPSTR отображается на дальний указатель,
состоящий из селектора и смещения. В 32-разрядной среде при использовании
сплошной (FLAT) модели памяти содержимое сегментных регистров
устанавливается один раз при запуске приложения и в дальнейшем
не изменяется (самим приложением). Для адресации в этом случае
используется только 32-разрядная компонента смещения.
Если ваша программа использует тип LPSTR, при ее переносе в среду
Windows NT вам не придется изменять исходные тексты, достаточно
выполнить новую трансляцию. Для этой операционной системы ключевое
слово FAR определено как пустое место:
#define FAR
Поэтому все дальние указатели, определенные с использованием этого
ключевого слова, автоматически превратятся в ближние (что и требовалось).
Если бы вы определяли дальний указатель на строку символов как
char _far *, вам бы пришлось удалять или переопределять
ключевое слово _far.
Типы данных в файле windows.h
Файл windows.h должен включаться во все исходные файлы приложений
Windows. Он содержит определение типов данных, символических имен
констант и прототипы функций программного интерфейса Windows.
Для создания мобильных приложений, которые вы сможете перенести
в среду Windows NT или аналогичную среду, поддерживающую программный
интерфейс Windows, следует пользоваться не стандартными типами
данных, реализованными в конкретной версии системы, а теми типами
данных, которые определены в файле windows.h.
Этот файл содержит описание базовых типов и производных, созданных
из базовых. Имена типов (как правило, это указатели) могут начинаться
с префикса. Префикс LP означает дальний указатель (Long Pointer),
префикс NP - ближний указатель (Near Pointer), и префикс P - указатель
без определения типа. Для константных типов данных (определенных
с ключевым словом const) после префикса добавляется буква "C",
например, LPCSTR.
Приведем список базовых типов данных, определенных в файле windows.h.
Тип данных | Определение типа в файле windows.h
| Описание |
BOOL | int | Булевый (двоичный)
|
BYTE | unsigned char | Байт
|
WORD | unsigned short | Беззнаковое целое размером 16 бит
|
DWORD | unsigned long | Беззнаковое целое размером 32 бит
|
UINT | unsigned int | Беззнаковое целое естественного для данной системы размера
|
Заметим, что в Windows версии 3.1 изменилось определение типа
данных WORD по сравнению с версией 3.0. В файле windows.h, предназначенном
для разработки приложений Windows версии 3.0, тип данных WORD
был определен следующим образом:
typedef unsigned int WORD; // Для Windows версии 3.0!
В обоих случаях (и для версии 3.0, и для версии 3.1) тип данных
отображается на беззнаковое целое длиной 16 бит. Но для Windows
NT типы данных unsigned int и unsigned short уже не эквивалентны.
Использование вместо них типа данных WORD упростит задачу переноса
исходных текстов приложений в 32-разрядную среду.
На основе приведенного выше набора базовых типов в файле windows.h
определены производные типы, которые являются указателями:
Тип данных | Определение типа в файле windows.h
| Описание |
PSTR | char NEAR * | Ближний указатель на символ типа char
|
NPSTR | char NEAR * | Ближний указатель на символ типа char
|
LPSTR | char FAR * | Дальний указатель на символ типа char
|
LPCSTR | const char FAR * |
Константный дальний указатель на символ типа char
|
PBYTE | BYTE NEAR * | Ближний указатель на байт
|
LPBYTE | BYTE FAR * | Дальний указатель на байт
|
PINT | int NEAR * | Ближний указатель на int
|
LPINT | int FAR * | Дальний указатель на int
|
PWORD | WORD NEAR * | Ближний указатель на беззнаковое целое размером 16 бит
|
LPWORD | WORD FAR * | Дальний указатель на беззнаковое целое размером 16 бит
|
PLONG | long NEAR * | Ближний указатель на знаковое целое размером 32 бит
|
LPLONG | long FAR * | Дальний указатель на знаковое целое размером 32 бит
|
PDWORD | DWORD NEAR * | Ближний указатель на беззнаковое целое размером 32 бит
|
LPDWORD | DWORD FAR * | Дальний указатель на беззнаковое целое размером 32 бит
|
LPVOID | void FAR * | Дальний указатель, для которого не определен тип данных
|
Файл windows.h содержит определения для многочисленных структур
данных, таких, как POINT, RECT, TEXTMETRICS и т. п. Для всех структур
данных определены указатели, например:
typedef struct tagPOINT
{
int x;
int y;
} POINT;
typedef POINT* PPOINT;
typedef POINT NEAR* NPPOINT;
typedef POINT FAR* LPPOINT;
Тип данных PPOINT в зависимости от используемой модели памяти
может быть как дальним, так и ближним указателем. Поэтому, для
того чтобы избежать неоднозначность в тех случаях, когда вам нужен,
например, дальний указатель, лучше воспользоваться типом LPPOINT.
Мы не будем перечислять все структуры данных, описанные в файле
windows.h, так как их очень много. Вы можете посмотреть определения
нужных вам структур непосредственно в файле windows.h, который
всегда находится в каталоге с именем include.
Еще один важный тип данных, определенный в файле windows.h, -
это различные идентификаторы (handle).
Для использования того или иного ресурса Windows вы должны получить
идентификатор нужного вам ресурса. Для получения идентификатора
вызывается одна из функций программного интерфейса Windows. Например,
для получения идентификатора контекста отображения можно воспользоваться
функцией GetDC:
HDC hdc;
hdc = GetDC(hwnd);
Само по себе полученное значение идентификатора не имеет для вас
никакого смысла. Идентификатор должен использоваться только для
ссылки на ресурс, например:
DrawText(hdc, (LPSTR)szBuf, nBufSize, &rc,
DT_CENTER | DT_VCENTER | DT_NOCLIP | DT_SINGLELINE);
Вы не можете изменять значение идентификатора ни самостоятельно,
ни с помощью каких-либо функций программного интерфейса Windows.
Некоторые ресурсы являются ограниченными, поэтому после того,
как вы их использовали, эти ресурсы следует отдать Windows с помощью
специально предназначенных для этого функций. Например, для того
чтобы отдать идентификатор контекста отображения, следует вызвать
функцию ReleaseDC:
ReleaseDC(hwnd, hdc);
Приведем список некоторых типов идентификаторов ресурсов:
Тип идентификатора | Описание
|
GLOBALHANDLE | Идентификатор блока глобальной памяти
|
HACCEL | Акселератор |
HBITMAP | Изображение в виде битового образа (bitmap)
|
HBRUSH | Кисть |
HCURSOR | Курсор |
HDC | Контекст устройства |
HDRVR | Драйвер устройства |
HFONT | Шрифт |
HGDIOBJ | Объект графического интерфейса GDI
|
HGLOBAL | Идентификатор блока глобальной памяти
|
HICON | Пиктограмма |
HLOCAL | Идентификатор блока локальной памяти
|
HMENU | Меню |
HMETAFILE | Метафайл |
HPALETTE | Палитра |
HPEN | Перо |
HRGN | Область |
HRSRC | Ресурс |
HSTR | Строка символов |
HTASK | Задача |
HWND | Окно |
LOCALHANDLE | Идентификатор блока локальной памяти
|
С некоторыми перечисленными выше идентификаторами вы уже знакомы,
с некоторыми вам еще только предстоит познакомиться в следующих
томах "Библиотеки системного программиста".
Имена констант в файле windows.h
Файл windows.h содержит определение большого количества имен символических
констант, таких, как коды сообщений, режимы работы и возможные
варианты параметров для различных функций программного интерфейса
Windows. Простое перечисление всех символических имен, определенных
в файле windows.h, заняло бы не один десяток страниц. Так как
наша книга не справочник, а скорее учебное пособие, и к тому же
размер книги ограничен, мы не будем подробно описывать каждое
символическое имя. Все необходимые сведения приведены в тексте
вместе с описанием соответствующих функций. Здесь же мы расскажем
только о префиксах символических имен.
Символические имена большинства констант, определенные в файле
windows.h и других файлах, включаемых в исходные тексты приложений
Windows, начинаются с префиксов, таких, как WM или WS. Имена некоторых
констант не имеют таких префиксов, например OPAQUE, TRANSPARENT
и т. п.
Приведем список некоторых префиксов имен констант, определенных
в файле windows.h.
Префикс символического имени константы |
Описание |
BI | Компрессия изображений bitmap
|
BN | Коды сообщений от кнопок
|
BS | Стили логических кистей
|
CB | Стили органа управления Combo Box
|
CBN | Коды сообщений от органа управления Combo Box
|
CBS | Стили при создании органа управления Combo Box
|
CE | Коды ошибок при передаче данных
|
CF | Форматы универсального буфера обмена данными Clipboard
|
COLOR | Системные цвета отдельных элементов пользовательского интерфейса Windows
|
CS | Стили класса окна |
DRIVE | Тип диска |
DS | Стили при создании диалоговых панелей
|
DT | Технология, использованная при создании устройства ввода/вывода
|
DT | Режимы форматирования при выводе текста функцией DrawText
|
HT | Коды, возвращаемые функцией DefWindowProc при обработке сообщения WM_NCHITTEST
|
ID | Идентификаторы команд диалоговой панели
|
IDC | Идентификаторы встроенных курсоров
|
IDI | Идентификаторы встроенных пиктограмм
|
MB | Флаги для функции MessageBox
|
META | Коды для метафайлов |
MM | Режимы отображения |
СС | Способность устройства рисовать различные кривые
|
OF | Константы для работы с файлами
|
PS | Стили пера |
RT | Типы ресурсов |
SB | Команды и константы для полосы просмотра (Scroll Bar)
|
SBS | Стили полосы просмотра
|
SC | Значения системных команд, передаваемых вместе с сообщением WM_SYSCOMMAND
|
SIZE | Константы для описания способа изменения размера окна
|
SM | Константы для определения системных метрик
|
SW | Константы для функции ShowWindow
|
TA | Константы для выбора способа выравнивания текста при его выводе с помощью функций TextOut и ExtTextOut.
|
VK | Коды виртуальных клавиш
|
WM | Сообщения Windows |
WS | Стили окна |
WS_EX | Расширенные стили окна
|
Имена параметров функций
Изобилие типов в приложениях Windows создает определенные трудности
для программиста. Ему приходится постоянно думать о соответствии
имен переменных типам переменных. Для облегчения работы программистов
рекомендуется для всех имен параметров функций и других переменных
использовать префиксы. Эти префиксы должны быть заданы маленькими
буквами. Приведем список некоторых префиксов, рекомендуемых для
различных типов данных:
Префикс | Тип данных |
atm | ATOM |
f | BOOL |
b | BYTE |
lpb | BYTE FAR* |
lpch | char FAR* |
dlgprc | DLGPROC |
dw | DWORD |
lpdw | DWORD FAR* |
haccl | HACCEL |
hbm | HBITMAP |
hbr | HBRUSH |
hcur | HCURSOR |
hdc | HDC |
hdrvr | HDRVR |
hdwp | HDWP |
hf | HFILE |
hfont | HFONT |
hgdiobj | HGDIOBJ |
hglb | HGLOBAL |
hhook | HHOOK |
hicon | HICON |
hinst | HINSTANCE |
hloc | HLOCAL |
hmenu | HMENU |
hmf | HMETAFILE |
hmod | HMODULE |
hkprc | HOOKPROC |
hpal | HPALETTE |
hpen | HPEN |
hrgn | HRGN |
hrsrc | HRSRC |
hstr | HSTR |
htask | HTASK |
hwnd | HWND |
n | int |
l | LONG |
lParam | LPARAM |
lpb | LPBYTE |
lpsz | LPCSTR |
lpn | LPINT |
lpl | LPLONG |
lpsz | LPSTR |
lpv | LPVOID |
lpw | LPWORD |
lResult | LRESULT |
npsz | NPSTR |
npb | PBYTE |
lppt | POINT FAR* |
lprc | RECT FAR* |
tmprc | TIMERPROC |
u | UINT |
wndenmprc | WNDENUMPROC |
wndprc | WNDPROC |
u или w | WORD |
wParam | WPARAM |
Так же как и при разработке программ для MS-DOS, при создании
приложений Windows вам следует правильно выбрать модель памяти.
Напомним основные различия между моделями памяти.
Модель памяти Tiny. Для этой модели создается один сегмент кода
и один сегмент данных, причем суммарный размер этих сегментов
не должен превышать 64 Кбайт. Эта модель памяти используется при
создании загрузочных модулей с расширением имени com. Вы не можете
использовать эту модель памяти при создании приложений Windows.
Модель памяти Small. Для этой модели создается один сегмент кода
и один сегмент данных, причем суммарный размер этих сегментов
не должен превышать 128 Кбайт. Размер массивов данных, созданных
с использованием этой модели, не должен превышать 64 Кбайт. Все
указатели являются ближними. Эта модель памяти пригодна для приложений
Windows. Все примеры приложений, приведенные в нашей книге, созданы
с использованием модели памяти Small.
Модель памяти Medium. В этой модели памяти создается один сегмент
данных и несколько сегментов кода. Размер массива данных не должен
превышать 64 Кбайт. Эта модель памяти часто используется при создании
относительно сложных приложений Windows, для которых невозможно
обойтись одним сегментом кода размером 64 Кбайт. Для вызова функций
в данной модели памяти используются 32-разрядные адреса, состоящие
из компонент <селектор:смещение>.
Модель памяти Compact. При использовании этой модели памяти можно
создать только один сегмент кода, но несколько сегментов данных.
Размер массива данных не должен превышать 64 Кбайт. Для вызова
функций, определенных внутри приложения, используется только компонента
смещения. Для адресации данных применяются 32-разрядные адреса.
Модель памяти Large. В этой модели памяти создается несколько
сегментов кода и несколько сегментов данных. Размер массива данных
по-прежнему не должен превышать 64 Кбайт. Для вызова функций и
адресации данных используются 32-разрядные адреса в формате <селектор:смещение>.
Модель памяти Huge. Эта модель памяти во всем аналогична модели
Large, но допускает работу с массивами неограниченного размера.
Операционная система Windows версии 3.0 могла быть запущена в
реальном режиме работы процессора. В этом случае сегменты данных
моделей памяти Compact, Large и Huge оказывались зафиксированными
в области реальных адресов. В защищенном режиме работы эта неприятность
не наблюдается.
Большинство приложений Windows использует либо модель памяти Small,
либо Medium, либо так называемую смешанная модель памяти.
Смешанная модель памяти. Для использования смешанной модели памяти
в программах MS-DOS используются такие ключевые слова, как _near
или _far. Приложения Windows должны пользоваться словами NEAR
или FAR.
В смешанной модели памяти вы можете комбинировать ближние и дальние
адреса данных и функций, добиваясь получения оптимальной производительности.
Следует отметить, что, строго говоря, вне зависимости от того,
какую модель памяти вы укажете при создании проекта, все равно
вам придется пользоваться смешанной моделью памяти. Даже при использовании
модели памяти Small ваше приложение будет вызывать функции программного
интерфейса Windows. Все эти функции в Windows версии 3.1 описаны
с ключевым словом _far и расположены в сегментах, принадлежащих
не вашему приложению, а операционной системе. Программа MS-DOS,
созданная с использованием модели памяти Small, не может содержать
дальних вызовов, так как все вызываемые ей функции расположены
в одном сегменте кода, а вызовы MS-DOS выполняются через прерывания.
Приложения Windows, напротив, не используют прерывания для вызова
операционной системы. Они всегда (при использовании любой модели
памяти) вызывают операционную систему с помощью команды дальнего
вызова.
При использовании редактора текста, входящего в состав систем
разработки Borland C++ for Windows версии 3.1 или Turbo C++ for
Windows версии 3.1, вы можете столкнуться с невозможностью просмотра
комментариев или текстовых строк, набранных с использованием символов
кириллицы. Это связано с тем, что указанные выше средства используют
для работы с текстом собственный шрифт, который не содержит символов
кириллицы.
Вы можете выйти из положения, заменив этот в общем-то неплохой
шрифт на другой, в котором есть символы кириллицы.
Для замены шрифта из главного меню системы разработки выберите
меню "Options". В меню "Options" выберите
строку "Environment". Затем на экране появится еще одно
(!) меню, в котором надо выбрать строку "Preferences...".
На экране появится диалоговая панель "Preferences" (рис.
8.1).
Рис. 8.1. Выбор нового шрифта
По умолчанию в меню "Font" выбран шрифт BorlandTE, в
котором нет символов кириллицы. Мы рекомендуем вам вместо этого
шрифта выбрать шрифт Courier Cyrillic, который есть в русской
версии Windows и который устанавливается практически всеми программами
локализации Windows, такими, как CyrWin. К сожалению, версия 3.1
системы разработки Borland C++ for Windows не может работать со
шрифтами TrueType. Этот недостаток устранен в следующей версии.
Посмотрите на исходный текст приложения 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 (в
инсталляторах). О том, как создавать собственные инсталляторы,
мы расскажем в отдельной главе в одной из следующих книг серии
"Библиотека системного программиста".
До появления такой среды разработки приложений Windows, как Borland
C++ версии 2.0, отладка приложений требовала наличия двух мониторов
или даже двух компьютеров. На одном мониторе отображался ход выполнения
программы, другой использовался для работы приложения.
Начиная с версии 2.0 в системе разработки Borland C++ появился
одноэкранный отладчик Turbo Debugger for Windows, значительно
упрощающий процесс отладки приложений. Для работы этого отладчика
достаточно одного компьютера и одного экрана (хотя наилучшие результаты
могут быть достигнуты только с двумя компьютерами).
Самый простой способ отладки приложений Windows тем не менее вообще
не требует применения отладчика. Он заключается в том, что вы
вставляете в разные места исходного текста приложения вызовы функции
MessageBox, с помощью которых прослеживаете ход выполнения программы.
Если же вам требуется узнать содержимое каких-либо переменных,
это можно сделать с помощью функции wsprintf. Вначале с помощью
функции wsprintf вы преобразуете интересующее вас значение в текстовую
строку, а затем выводите эту строку функцией MessageBox. В некоторых
случаях достаточно ограничиться выдачей звукового сигнала, для
чего можно вызвать функцию MessageBeep. Примеры вызова функций
MessageBox, wsprintf и MessageBeep вы можете найти в приложениях,
описанных в нашей книге.
Однако для отладки более сложных приложений вы не сможете ограничиться
выдачей диагностических сообщений. Тогда, если вы программист,
который только начинает создавать приложения для Windows, мы рекомендуем
вам воспользоваться одноэкранным отладчиком Turbo Debugger for
Windows, который входит в комплект поставки системы разработки
Borland C++ for Windows версии 3.1 или Turbo C++ for Windows.
Учтите, что указанный отладчик не работает с видеоадаптером EGA.
Поэтому, если у вас установлен такой видеоадаптер, мы рекомендуем
заменить его на другой. Лучше всего приобрести видеоадаптер SVGA
с ускорителем для Windows, в котором многие графические операции
выполняются аппаратно, благодаря чему скорость вывода изображения
сильно повышается. Стоимость такого видеоадаптера может составлять
порядка 100 долларов. В крайнем случае на первом этапе вы можете
использовать видеоадаптер VGA, однако в этом случае вам не будут
доступны режимы с высоким разрешением и с большим количеством
цветов.
С помощью отладчика вы сможете выполнить приложение в пошаговом
режиме, выполнить обратную трассировку, установить точки прерывания,
просмотреть состояние переменных, содержимое стека, файлов данных,
изменить значение переменных и сделать многое другое.
Для запуска отладчика из среды разработки выберите из меню "Run"
строку "Debugger". Перед этим вы можете задать параметры
командной строки для отлаживаемого приложения. Для этого из указанного
меню надо выбрать строку "Debugger Arguments...".
После выбора строки "Debugger" на экране появится сообщение
о загрузке отладчика, после чего экран переключится в текстовый
режим. К сожалению, отладчик Turbo Debugger for Windows, который
поставляется в комплекте со средой разработки Borland C++ for
Windows версии 3.1, может работать только в текстовом режиме (среда
разработки Borland C++ for Windows версии 4.0 содержит, помимо
отдельного отладчика Turbo Debugger for Windows, отладчик, который
встроен в среду разработки и работает в обычном окне Windows в
графическом режиме). Несмотря на это, указанный отладчик не способен
работать с видеоконтроллером EGA.
После запуска отладчика вы попадаете в среду, знакомую вам по
отладчику Turbo Debugger для MS-DOS. В отладчике Turbo Debugger
for Windows используются почти такие же функциональные клавиши
и меню, что и в версии для MS-DOS. Из-за недостатка места в книге
мы не будем описывать работу с отладчиком Turbo Debugger. Если
вы разрабатывали программы для MS-DOS, вы скорее всего уже пользовались
этим отладчиком. Поэтому мы ограничимся только несколькими замечаниями,
которые относятся к отладке приложений Windows.
Первое замечание касается отладки функций обратного вызова, таких,
как функция окна WndProc.
Так как структура стандартного приложения Windows отличается от
линейной структуры программы MS-DOS, для отладки функций обратного
вызова вам надо установить в них точки останова. В противном случае
вы никогда не сможете отладить такие функции - при пошаговом выполнении
приложения вы окажетесь в цикле обработки сообщений. Добраться
до функций обратного вызова через пошаговое выполнение приложения
невозможно, так как эти функции вызываются не из приложения, а
из операционной системы Windows.
Если функция окна расположена в отдельном файле, для установки
точки останова вам надо перейти в режим просмотра этого файла.
Для просмотра модуля, расположенного в отдельном файле, выберите
из меню отладчика "View" строку "Module".
Вы окажитесь в диалоговой панели, с помощью которой можно выбрать
имя модуля. Приложения, приведенные в нашей книге, используют
для функции окна файл с именем wndproc.cpp, поэтому в появившейся
диалоговой панели выберите строку "WNDPROC".
После этого в окне отладчика вы увидите исходный текст функции
окна. Выберите нужное вам место и установите точку останова, нажав
клавишу <F2>. Далее запустите приложение на выполнение,
нажав клавишу <F9>. Когда будет достигнута установленная
вами точка останова, отладчик переключится в пошаговый режим.
Второе замечание относится к просмотру экрана выполняющегося приложения.
Для переключения в режим просмотра экрана приложения и обратно
используйте комбинацию клавиш <Alt+F5>. При переключении
в верхней части экрана авторы практически всегда наблюдали "мусор".
Это не есть результат неправильной работы вашего приложения, поэтому,
если можете, не обращайте на него никакого внимания. Возможно,
в следующих версиях одноэкранного отладчика Borland сумеет сделать
правильное восстановление экрана Windows. Если же подобная "особенность"
отладчика вам кажется недопустимой, единственный выход - отладка
с помощью двух адаптеров или, что лучше, с помощью двух компьютеров.
Однако для начала вам лучше работать с одноэкранным отладчиком.
Отладчик Turbo Debugger for Windows имеет дополнительные возможности
по сравнению с версией для MS-DOS. В частности, с помощью этого
отладчика можно протоколировать сообщения, которые получают и
посылают окна вашего приложения, работать с глобальной и локальной
памятью, просматривать полный список загруженных модулей, отлаживать
библиотеки динамической загрузки DLL и просматривать содержимое
любого селектора.
Для просмотра списка сообщений, получаемых функцией окна, выберите
в отладчике из меню "View" строку "Windows Message".
На экране появится диалоговая панель "Windows Message",
разделенная на три части. В левой верхней части следует указать
имя функции окна или идентификатор окна, для которого нужно протоколировать
сообщения. В правой верхней части окна можно выбирать, какие сообщения
следует отображать, а какие - игнорировать. Нижняя часть окна
предназначена для отображения получаемых сообщений.
Выберите мышью левую верхнюю часть окна "Windows Message"
и нажмите комбинацию клавиш <Alt+F10>. На экране появится
меню из трех строк:
Add...
Remove
Delete all
Выберите строку "Add...". На экране появится диалоговая
панель "Add window or handle to watch". В этой диалоговой
панели установите переключатель "Identify by" в положение
"Window proc" и в поле "Window identifier"
введите имя функции окна, например wndproc. Затем нажмите кнопку
"OK".
С помощью строк "Remove" и "Delete all" вы
можете удалить отдельный или все идентификаторы или имена функций,
для которых нужно протоколировать получаемые сообщения.
В правой верхней части диалоговой панели "Windows Message"
находится надпись "Log all messages", которая означает,
что будут протоколироваться все сообщения, поступающие в указанные
вами окна. Если сообщений слишком много, вы можете выбрать для
отображения только некоторые классы сообщений. Для этого выберите
мышью правую верхнюю часть диалоговой панели "Windows Message"
и нажмите комбинацию клавиш <Alt+F10>. Появится уже знакомое
вам меню:
Add...
Remove
Delete all
Выберите строку "Add...". С помощью переключателя "Message
class" вы можете выбрать различные классы отображаемых (протоколируемых)
сообщений:
Класс сообщения | Описание |
All Messages | Все сообщения
|
Mouse | Сообщения от мыши |
Window | Сообщения от системы управления окнами (такие, как WM_PAINT и WM_CREATE)
|
Input | Сообщения от клавиатуры, системного меню, полос просмотра или кнопок изменения размера
|
System | Системные сообщения
|
Initialization | Сообщения, которые появляются при создании приложением окна или диалоговой панели
|
Clipboard | Сообщения, которые создаются приложением при доступе к универсальному буферу обмена Clipboard или окну другого приложения
|
DDE | Сообщения, которые возникают в результате динамического обмена данными между приложениями с использованием механизма DDE
|
Non-client | Сообщения, которые создаются Windows для работы с внешней (non-client) областью окна (такие, как WM_NCHITTEST или WM_NCCREATE)
|
Other | Остальные сообщения, не попавшие в перечисленные выше классы, такие, как сообщения интерфейса MDI
|
Single Message | Любое выбранное вами сообщение. Символическое имя или десятичный идентификатор сообщения следует указать в поле "Single Message Name"
|
С помощью переключателя "Action" вы можете задать действие,
выполняемое отладчиком при перехвате сообщения. По умолчанию включен
режим "Log", что соответствует протоколированию сообщения
и отображению его в нижней части диалоговой панели "Windows
Messages". Режим "Break" позволяет вам организовать
останов приложения по сообщению.
Остальные возможности отладчика будут рассмотрены позже.
|