
- •5. Программирование в операционной системе windows
- •5.1. Основные концепции Windows
- •Контрольные вопросы
- •5.2. Архитектура, управляемая событиями
- •Контрольные вопросы
- •5.3. Примеры программ.
- •Int winapi WinMain (hinstance hInstance,
- •Int CmdShow)
- •Int winapi WinMain (hinstance hInstance,
- •Int MessageBox (hwnd hWnd, lpctstr lpText, lpctstr lpCaption, uint uType).
- •Int winapi WinMain(hinstance hInstance, hinstance hPrevInstance, lptstr lpCmdLine, int nCmdShow)
- •If (!RegisterClassEx(&wc))
- •If (!hMainWnd)
- •Int nWidth,
- •Int nHeight,
- •Контрольные вопросы
- •5.4. Программирование графики
- •Bool InvalidateRect (hwnd hWnd, const rect* lpRect, bool bErase);
- •Bool InvalidateRgn (hwnd hWnd, hrgn hRgn, bool bErase);
- •Bool ClientToScreen(hwnd hWnd, lpoint lpPoint); bool ScreenToClient(hwnd hWnd, lpoint lpPoint);
- •Контрольные вопросы
- •5.5. Рисование линий, фигур, текста
- •GetCurrentPositionEx (hdc, &pt);
- •Bool Polyline (hdc hdc, const point* lppt, int cPoints);
- •Bool PolylineTo (hdc hdc, const point* lppt, dword cPoints);
- •Bool Arc (hdc hdc, int xLeft, int yTop, int xRight, int yBottom, int xStart, int yStart, int xEnd, int yEnd);
- •SetArcDirection (hdc, ad_clockwise);
- •Bool Rectangle (hdc hdc, int xLeft, int yTop, int xRight int yBottom);
- •Bool Ellipse (hdc hdc, int xLeft, int yTop, int xRight, int yBottom);
- •Bool Polygon (hdc hdc, const point * lpPoints, int nCount);
- •Контрольные вопросы
- •5.6. Средства ввода
- •If (!RegisterClassEx(&wc))
- •X, y, width, height, hParent,
- •If (!hWnd)
If (!RegisterClassEx(&wc))
{
MessageBox(NULL, "Класс окна не зарегистрирован", "Ошибка", MB_OK);
return 0;
};
// Создаем основное окно приложения
hMainWnd = CreateWindow(
szClassName,
"Да здравствует приложение!",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
0,
CW_USEDEFAULT,
0,
(HWND)NULL,
(HMENU)NULL,
(HINSTANCE)hInstance,
NULL
);
If (!hMainWnd)
{
MessageBox(NULL, "Главное окно не создано", "Ошибка", MB_OK);
return 0;
};
// Показываем созданное окно
ShowWindow(hMainWnd, nCmdShow);
// Выполняем цикл обработки сообщений до закрытия приложения
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
};
return msg.wParam;
}
//---------------------------------------------------------------------------
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
HDC hDC;
PAINTSTRUCT ps;
RECT rect;
switch (uMsg)
{
case WM_PAINT:
hDC = BeginPaint(hWnd, &ps);
GetClientRect(hWnd,&rect);
DrawText(hDC, "Hello World!", -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
EndPaint(hWnd, &ps);
break;
case WM_CLOSE:
DestroyWindow(hWnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default: return DefWindowProc(hWnd, uMsg, wParam, lParam);
};
return 0;
}
После компиляции и запуска программы на экране появтся окно, показанное на рис. 5.3.
Простая программа для Windows
Рис. 5.3
Обсудим теперь подробно содержание программы.
В программе имеется две функции: WinMain и WndProc. WinMain – это точка входа в программу. WndProc – это оконная процедура для главного окна программы. Оконная процедура инкапсулирует код, отвечающий за ввод информации, обычно осуществляемый при помощи клавиатуры или мыши, а также – за вывод информации на экран.
В программе отсутствуют инструкции для непосредственного вызова WndProc, т.к. оконная процедура вызывается только из Windows. Однако в WinMain имеется ссылка на WndProc (адрес оконной процедуры присваивается полю wc.lpfnWndProc), поэтому прототип функции WndProc объявлен в самом начале программного файла, еще до описания функции WinMain.
Обратим внимание на идентификаторы, написанные полностью прописными буквами. Эти идентификаторы задаются в заголовочных файлах Windows. Некоторые из них содержат двух- или трехбуквенный префикс, завершаемый символом подчеркивания, например, CS_HREDRAW, IDI_APPLICATION, IDC_ARROW, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT. Это просто числовые константы. Некоторые из этих категорий приведены в таблице 5.2.
Таблица 5.2. Префиксы для числовых констант
Префикс |
Категория |
CS_ |
Опция стиля класса |
CW_ |
Опция создания окна |
DT_ |
Опция рисования окна |
IDC_ |
Идентификатор предопределенного курсора |
IDI_ |
Идентификатор предопределенной иконки |
WM_ |
Сообщение окна |
WS_ |
Стиль окна |
Также следует обратить внимание на типы данных, специфичные для системы Windows. Некоторые из них были приведены в таблице 5.1.
5.3.3. Регистрация класса окна. Сразу после входа в функцию WinMain создается и регистрируется класс главного окна приложения. Для этого необходимо заполнить структуру типа WNDCLASSEX, а затем передать адрес этой структуры в виде аргумента функции RegisterClassEx.
Структура WNDCLASSEX имеет двенадцать полей:
typedef struct tagWNDCLASSEX
{
UINT cbSize; // размер данной структуры в байтах
UINT style; // стиль класса окна
WNDPROC lpfnWndProc; // указатель на функцию окна (оконную процедуру)
int cbClsExtra; // число дополнительных байтов, которые дожны быть
// распределены в конце структуры класса
int cbWndExtra; // число дополнительных байтов, которые дожны быть
// распределены вслед за экземпляром окна
HINSTANCE hInstance; // дескриптор экземпляра приложения, в котором находится
// оконная процедура для этого класса
HICON hIcon; // дескриптор пиктограммы
HCURSOR hCursor; // дескриптор курсора
HBRUSH hbrBackground; // дексриптор кисти, используемой для закраски фона окна
LPCTSTR lpszMenuName; // указатель на строку, содержащую имя меню, применяемого
// по умолчанию для этого класса
LPCTSTR lpszClassName; // указатель на строку, содержащую имя класса окна
HICON hIconSm; // дескриптор малой пиктограммы
} WNDCLASSEX;
Рассмотрим назначение полей структуры WNDCLASSEX.
Значение первого поля, cbSize, должно быть равно длине структуры.
Второе поле, style, может содержать в своем значении один или несколько стилей, наиболее употребительные стили перечисленны в таблице 5.3.
Таблица 5.3. Стили класса окна
Стиль |
Описание |
CS_GLOBALCLASS |
Создать класс, доступный всем приложениям. Обычно этот стиль применяется для создания определяемых пользователем элементов управления в DLL |
CS_HREDRAW |
Перерисовывать все окно, если изменен размер по горизонтали |
CS_NOCLOSE |
Запретить команду Close в системном меню |
CS_OWNDC |
Выделить уникальный контекст устройства для каждого окна, созданного при помощи этого класса |
CS_VREDRAW |
Перерисовывать все окно, если изменен размер по вертикали |
В заголовочных файлах Windows идентификаторы, начинающиеся с префикса CS_, задаются в виде 32-разрядной константы, в которой только один разряд установлен в единичное состояние. Например, константа CS_VREDRAW задана как 00001, а CS_HREDRAW – как 00002. Подобные конмогут объединяться с помощью операции ИЛИ языка С++.
В рассматриваемой программе используется комбинация стилей CS_VREDRAW | CS_HREDRAW. Это означает, что все окна этого класса должны целиком перерисовываться при изменении как горизонтального, так и вертикального размеров окна. Если попробовать изменить размеры окна «Простое приложение для Windows», то можно увидеть, что строка текста «Для завершения закройте окно» переместится в новый центр окна. Механизм уведомления оконной процедуры об изменении размеров окна будет рассмотрен позже.
Третье поле, lpfnWndProc, содержит адрес оконной процедуры (в нашей программе это – WndProc).
Четвертое cbClsExtra и пятое cbWndExtra поля используются крайне редко, а назначение шестого поля, hInstance, очевидно, поэтому их обсуждать не будем.
Седьмое поле, hIcon, содержит дескриптор пиктограммы, которая предназначена для этого класса окна. Значение hIcon обычно получают вызовом функции LoadIcon, которая имеет следующий прототип:
HICON LoadIcon (HINSTANCE hInstance, LPCTSTR lpIconName).
Эта функция загружает ресурс пиктограммы, заданной параметром lpIconName, из экземпляра приложения, указанного параметром hInstance. Функцию можно использовать также для загрузки одной из системных пиктограмм, если передать первому аргументу значение NULL. В этом случае второй аргумент должен содержать константу, идентификатор которой начинается с префикса IDI_ («идентификатор значка» - ID for icon). Возможные значения второго аргумента для системных пиктограмм приведены в таблице 5.4.
Таблица 5.4. Идентификаторы системных пиктограмм
Значение |
Описание |
IDI_APPLICATION |
Пиктограмма приложения по умолчанию |
IDI_ASTERISK |
Тог же, что и IDI_INFORMATION |
IDI_ERROR |
Пиктограмма в виде белого креста на фоне красного круга. Используется в серьезны предупреждающих сообщениях |
IDI_EXCLAMATION |
Тог же, что и IDI_WARNING |
IDI_HAND |
Тог же, что и IDI_ERROR |
IDI_INFORMATION |
Пиктограмма «i», которая используется в информационных сообщениях |
IDI_QUESTION |
Пиктограмма «?» |
IDI_WARNING |
Пиктограмма «!», которая используется в предупреждающих сообщениях |
IDI_WINLOGO |
Логотип Windows |
Восьмое поле, hCursor, содержит дескриптор курсора мыши, используемого приложением в клиентской области окна. Значение hCursor обычно получают с помощью вызова функции LoadCursor, имеющей следующий прототип:
HCURSOR LoadCursor (HINSTANCE hInstance, LPCTSTR lpCursorName).
Эта функция загружает ресурс курсора, заданный вторым параметром (lpCursorName), из экземпляра приложения, заданного первым параметром(hInstance).
Функцию можно также использовать для загрузки одного из системных курсоров, если передать первому аргументу значение NULL. Значение второго аргумента при этом выбирается из таблицы 5.5.
Таблица 5.5. Идентификаторы курсора
Значение |
Описание |
IDC_APPSTARTING |
Стандартная стрелка и малые песочные часы |
IDC_ARROW |
Стандартная стрелка |
IDC_CROSS |
Перекрестье |
IDC_HELP |
Стрелка и вопросительный знак |
IDC_IBEAM |
Текстовый двутавр |
IDC_NO |
Перечеркнутый кружок |
IDC_SIZEALL |
Четырехконечная стрелка |
IDC_SIZENESW |
Двухконечная стрелка, указывающая на северо-восток и юго-запад |
IDC_SIZENS |
Двухконечная стрелка, указывающая на север и юг |
IDC_SIZENWSE |
Двухконечная стрелка, указывающая на северо-запад и юго-восток |
IDC_SIZEWE |
Двухконечная стрелка, указывающая на запад и восток |
IDC_UPARROW |
Вертикальная стрелка |
IDC_WAIT |
Песочные часы |
Девятое поле, hbrBackground, содержит дескриптор кисти, используемой приложением для закраски фона и клиентской области окна. Кисть - (brush) – это графический объект, который представляет собой шаблон пикселов различных цветов, используемый для закрашивания области. В Windows имеется несколько стандартных кистей. Вызов функции GetStockObject с аргументом WHITE_BRUSH возвращает дескриптор белой кисти. Возвращаемое значение имеет тип HGDIOBJ, поэтому необходимо преобразование его к типу HBRUSH.
Десятое поле, lpszMenuName, указывает на строку, содержащую имя меню, применяемого по умолчанию для данного класса. Рассматриваемая программа не имеет меню, поэтому поле установлено в NULL.
Одиннадцатое поле, lpszClassName, указывет на строку, содержащую имя класса. Это имя должно использоваться в параметре lpClassName функции CreateWindow.
Двенадцатое поле, hIconSm, содержит дескриптор малой пиктограммы, которая предназначена для использования в строке заголовка окон, созданных при помощи этого класса. Размеры пиктограммы должны быть 16 16 пикселов. Если поле равно NULL, то система ищет ресурс пиктограммы, указанный полем hIcon, чтобы сформировать малую пиктограмму из него.
Итак, с заполнением структуры класса окна мы разобрались. Осталось зарегистрировать подготовленный класс, вызвав функцию RegisterClassEx, передав ей параметром структуру WNDCLASSEX5.
5.3.4. Создание окна. Если регистрация класса окна прошла успешно, то следующий этап – создание окна. Для этого вызывается функция CreateWindow, прототип которой приведен ниже:
HWND CreateWindow (
LPCTSTR lpClassName, // имя зарегистрированного класса
LPCTSTR lpWindowName, // имя окна
DWORD dwStyle, //стиль окна
int x, //горизонтальная позиция
int y, //вертикальная позиция
int nWidth, //ширина окна
int Height, //высота окна
HWND hWndParent, //дескриптор родительского окна
HMENU hMenu, // дескриптор меню или идентификатор элемента управления
HINSTANCE hInstance, //дескриптор экземпляра приложения
LPVOID lParam //указатель на данные, передаваемые в сообщении WM_CREATE
).
Рассматривая назначение параметров, не будем забывать, что функция CreateWindow позволяет создавать не только основное окно приложения, но и любые другие окна, включая окна стантартных классов, с помощью которых реализуются элементы управления Windows.
Первый параметр, lpClassName, - это указатель на строку, содержащую допустимое имя класса. Таким именем может быть либо имя класса, зарегистрированное ранее при помощи функции RegisterClassEx ли RegisterClass, либо имя одного из стандартных классов, перечисленных в таблице 5.6
Таблица 5.6. Стандартные классы окон
Класс |
Описание |
Префикс в обозначении стилей |
BUTTON |
Прямоугольное окно кнопки, группы, флажка, переключателя или пиктограммы |
BS_ |
COMBOBOX |
Элемент управления, объединяющий элементы LISTBOX и EDIT. В поле редактирования отображается выбранная строка из LISTBOX |
CBS_ |
EDIT |
Прямоугольное окно (окно редактирования), предназначенное для ввода текста с клавиатуры |
ES_ |
LISTBOX |
Прямоугольное окно со списком строк, из которого пользователь может выбрать любую строку |
LBS_ |
MDICLIENT |
Клиентское окно многодокументного интерфейса. Это окно получает сообщения, которые управляют дочерними окнами в MDI - приложении |
|
RICHEDIT |
Элемент управления Rich Edit версии 1.0. В дополнение к возможностям элемента EDIT позволяет редактировать текст с разными шрифтами и стилями |
ES_ |
RICHEDITCLASS |
Элемент управления Rich Edit версий 2.0, 3.0. Усовершенствованная версия элемента RICHEDIT с дополнительными возможностями |
ES_ |
SCROLLBAR |
Элемент управления линейкой прокрутки |
SBS_ |
STATIC |
Элемент управления статическим текстом. Применяется для размещения в окне текста или рамок |
SS_ |
Второй параметр, lpWindowName, - это указатель на строку, содержащую имя окна. Место отбражения имени зависит от вида окна. Например, для главного окна приложения оно выводится как заголовок окна, а для окна стандартного класса BUTTON размещается по центру кнопки.
Третий параметр, dwStyle, позволяет указывать стиль окна, сотоящий из значений, указанных в таблице 5.7.
Таблица 5.7. Стили окна
Обозначение стиля |
Описание |
WS_BORDER |
Создать окно с рамкой в виде тонкой линии |
WS_CAPTION |
Создать окно, которое имеет область заголовка (включает стиль WS_BORDER) |
WS_CHILD |
Создать дочернее окно. Окно этого стиля не может иметь полосу меню и не может иметь стиль WS_POPUP |
WS_CLIPCHILDREN |
Исключить перерисовку дочерних окон, принадлежащих данному родительскому окну |
WS_CLIPSIBLINGS |
Исключить перерисовку соседних дочерних окон при перерисовке данного дочернего окна |
WS_DLGFRAME |
Создать окно, имеющее рамку со стилем, типичным для диалоговых окон. Окно этого стиля не может иметь область заголовка |
WS_GROUP |
Считать данное окно первым в группе элементов управления (обычно группируются переключатели) |
WS_HSCROLL |
Создать окно с горизонтальной линейкой прокрутки |
WS_MAXIMIZE |
Создать окно, которое первоначально является развернутым |
WS_MAXIMIZEBOX |
Создать окно с кнопкой развертывания |
WS_MINIMIZE |
Создать окно, которое первоначально является свернутым |
WS_MINIMIZEBOX |
Создать окно с кнопкой свертывания |
WS_OVERLAPPED |
Создать перекрывающееся окно. Окно этого стиля имеет область заголовка и рамку |
WS_OVERLAPPEDWINDOW |
Сочетание стилей WS_OVERLAPPED, WS_CAPTION, WS_SYSMENU, WS_THICKFRAME, WS_MINIMIZEBOX и WS_MAXIMIZEBOX |
WS_POPUP |
Создать всплывающее окно. Этот стиль не может использоваться со стилем WS_CHILD |
WS_POPUPWINDOW |
Сочетание стилей WS_BORDER, WS_POPUP и WS_SYSMENU. Чтобы сделать системное окно видимым, необходимо добавить стиль WS_CAPTION |
WS_SYSMENU |
Создать окно с системным меню в области заголовка |
WS_TABSTOP |
Стиль указывает, что на окне может остановиться фокус ввода, перемещаемый при помощи клавиши TAB |
WS_THICKFRAME |
Создать окно с рамкой, которая позволяет изменять его размеры |
WS_VISIBLE |
Создать окно, которое сразу же является видимым |
WS_VSCROLL |
Создать окно с вертикальной линейкой прокрутки |
В рассматриваемой программе используется стандартный стиль для главного окна приложения - WS_OVERLAPPEDWINDOW. Это обычное перекрывающееся окно с заголовком, системным меню, расположенным в левой части строки заголовка, кнопками для сворачивания , разворачивания и закрытия окна справа на строке заголовка и «толстой» рамкой, позволяющей изменять размеры окна.
Четвертый параметр, х, задает горизонтальную позицию левого верхнего угла окна. Для главного окна позиции x и y определяются в экранных координатах, а для дочерних окон и элементов управления координаты отсчитываются относительно левого верхнего угла родительского окна.
Если позиция х не важна, то можно установить значение CW_USEDEFAULT. В этом случае Windows использует значения x и y по умолчанию. Это означает, что система располагает следующие друг за другом перекрывающиеся окна, равномерно отступая по горизонтали и вертикали от левого верхнего угла экрана.
Пятый параметр, y, задает вертикальную позицию левого верхнего угла экрана. Если параметр х имеет значение CW_USEDEFAULT, то значение параметра y игнорируется.
Шестой параметр, nWidth, задает ширину окна в пикселах. Если ему присвоено значение CW_USEDEFAULT, то система будет использовать значения nWidth и nHight по умолчанию.
Седьмой параметр, nHight, задает высоту окна в пикселах. Если параметр nWidth установлен в CW_USEDEFAULT, то значение nHight игнорируется.
Восьмой параметр, nWndParent, в рассматриваемой программе имеет значение NULL, поскольку у главного окна программы отсутствует родительское окно. Заметим, что, если между двумя окнами существует связь типа родительское – дочернее, дочернее окно всегда появляется только на поверхности родительского.
Девятый параметр, hMenu, содержит дескриптор меню окна или идентификатор элемента управления. Интерпретация значения параметра зависит от вида окна.
Если приложение использует меню, определенное в классе окна (поле lpszMenuName в структуре WNDCLASSEX), то параметру hMenu необходимо присвоить значение NULL.
Если создаваемое окно относится к элементу управления, то параметру hMenu передается целочисленное значение, которое далее используется как идентификатор созданного элемента. Этот идентификатор, например, будет содержаться в сообщениях WM_COMMAND, поступающих от элемента управления.
Десятому параметру, hInstance, должен быть присвоен дескриптор экземпляра приложения, переданный программе в качестве аргумента функции WinMain.
Последний параметр, lParam, в рассматриваемом примере тоже имеет значение NULL. При необходимости он может быть использован в качестве указателя на дополнительные данные, передаваемые окну в момент его создания с помощью сообщения WM_CREATE.
Итак, функция CreateWindow вызвана. Отработав, она возвращает дескриптор созданного окна. Если по какой-то причине создать окно не удалось, то функция возвращает значение NULL. Поэтому рекомендуется проверять возвращаемое функцией значение и в случае неудачи выдавать соответствующее сообщение, используя уже знакомую функцию MessageBox.
Использование функции CreateWindowEx. Для создания окна вместо функции CreateWindow может быть вызвана функция CreateWindowEx, прототип которой приведен ниже:
HWND CreateWindowEx (
DWORD dwExStyle,
LPCTSTR lpClassName,
LPCTSTR lpWindowName,
DWORD dwStyle,
int x,
int y,