Идентификаторы, написанные прописными буквами



В дальнейшем вы обратите внимание на использование в HELLOWIN.H нескольких идентификаторов, полностью написанных прописными буквами. Эти идентификаторы задаются в заголовочных файлах Windows. Некоторые из этих идентификаторов содержат двухбуквенный или трехбуквенный префикс, за которым следует символ подчеркивания:

CS_HREDRAW, CS_VREDRAW, IDC_ARROW.

Это просто числовые константы. Префикс показывает основную категорию, к которой принадлежат константы, как показано в данной таблице:

Префикс Категория
CS Опция стиля класса
IDI Идентификационный номер иконки
IDC Идентификационный номер курсора
WS Стиль окна
CW Опция создания окна
WM Сообщение окна
SND Опция звука
Опция рисования текста

 

Программируя для Windows, почти никогда не нужно запоминать числовые константы. Фактически для любой числовой константы, которая используется в Windows, в заголовочных файлах имеется идентификатор.

Новые типы данных

Несколько других идентификаторов в HELLOWIN.C являются новыми типами данных; они также определяются в заголовочных файлах с помощью либо инструкций typedef, либо инструкций #define.

Тип данных UINT, использованный в качестве второго параметра WndProc — это просто беззнаковое целое, которое в Windows является 32-разрядным. Тип данных PSTR, использованный в качестве третьего параметра WinMain, является указателем на строку символов, т. е. char*.

Третий и четвертый параметры WndProc определяются как WPARAM и LPARAM соответственно. Происхождение этих имен требует небольшого экскурса в историю. Когда Windows была 16-разрядной системой, третий параметр WndProc определялся как WORD, что означало 16-разрядное беззнаковое короткое целое, а четвертый параметр определялся как LONG, что означало 32-разрядное знаковое длинное целое, и в этом смысл префиксов "W" и "L" у слова "РАRАМ". В Windows имя WPARAM определяется как UINT, a LPARAM как LONG (что представляет из себя просто тип данных длинное целое языка С), следовательно оба параметра оконной процедуры являются 32-разрядными. Это может оказаться несколько неудобным, поскольку тип данных WORD в Windows по-прежнему определяется как 16-разрядное беззнаковое короткое целое, следовательно, префикс "W" у слова "PARAM" создает некоторую путаницу.

Функция WndProc возвращает значение типа LRESULT. Оно определено просто как LONG. Функция WinMain получает тип WINAPI (как и любая другая функция Windows, которая определяется в заголовочных файлах), а функция WndProc получает тип CALLBACK. Оба эти идентификатора определяются как stdcall, что является ссылкой на особую последовательность вызовов функций, которая имеет место между самой операционной системой Windows и ее приложением.

В HELLOWIN также использованы четыре структуры данных, определяемых в заголовочных файлах Windows. Этими структурами данных являются:

Первые две структуры данных используются в WinMain для определения двух структур, названных msg и wndclass. Две вторые используются в WndProc для определения структур ps и rect.

Структура Значение Имя переменной
MSG Структура сообщения msg
WNDCLASSEX Структура класса окна wndclass
PAINTSTRUCT Структура рисования ps
RECT Структура прямоугольника rect

 

Описатели

Имеется еще три идентификатора, которые пишутся прописными буквами и предназначены для разных типов описателей (handles).

Описатели в Windows используются довольно часто (описатель HICON (описатель иконки), описатель HCURSOR (описатель курсора мыши) и описатель HBRUSH (описатель графической кисти)).

Описатель — это просто число (обычно длиной в 32 разряда), которое ссылается на объект. Описатели в Windows напоминают описатели файлов при программировании на традиционном С в MS-DOS. Программа почти всегда получает описатель путем вызова функции Windows. Программа использует описатель в других функциях Windows, чтобы сослаться на объект. Действительное значение описателя весьма важно для вашей программы, но модуль Windows, который обеспечивает программу описателем, "знает", как его использовать для ссылки на объект.

Идентификатор Значение
HINSTANCE Описатель экземпляра (instance) самой программы,
HWND Описатель окна
НDС Описатель контекста устройства

Венгерская нотация

Как вы могли заметить, некоторые переменные в HELLOWIN.C имеют своеобразные имена. Например, имя szCmdLine — параметр WinMain.

Многие программисты для Windows используют соглашения по именованию переменных, названные условно Венгерской нотацией, в честь легендарного программиста Microsoft Чарльза Симони. Все очень просто: имя переменной начинается со строчных буквы или букв, которые отмечают тип данных переменной. Например, префикс sz в szCmdLine означает, что строка завершается нулем (string terminated by zero). Префикс h в hInstance и hfnInstance означает описатель (handle); префикс i в iCmdShow означает целое (integer). В двух последних параметрах WndProc также используется венгерская нотация, хотя, как уже говорилось раньше, wParam правильнее следовало бы назвать uiParam (беззнаковое целое — unsigned integer). Но поскольку эти два параметра определяются через типы данных WPARAM и LPARAM, было решено сохранить их прежние имена.

При обозначении переменных структуры удобно пользоваться именем самой структуры (или аббревиатурой имени структуры) и строчными буквами, используя их либо в качестве префикса имени переменной, либо как имя переменной в целом. Например, в функции WinMain в HELLOWIN.C переменная msg относится к структуре типа MSG; wndclass — к структуре типаWNDCLASSEX. В функции WndProc, переменная ps относится к структуре PAINTSTRUCT, rect - к RECT.

Префикс Тип данных  
с символ
by BYTE (беззнаковый символ)
n короткое целое
x, у целое х, целое y (используется в качестве координат х и )у
сх, су целое (используется в качестве длины х или у), с означает "счет" — (count).
b или f BOOL (булево целое); f означает "флаг" — (flag)
w WORD (беззнаковое короткое целое)
l LONG (длинное целое)
dw DWORD (беззнаковое длинное целое)
fn функция
s cтрока
sz строка, завершаемая нулем
h описатель (handle)
р указатель (pointer)

 

Венгерская нотация помогает избегать ошибок в программе еще до ее компоновки. Поскольку имя переменной описывает и саму переменную и тип ее данных, то намного снижается вероятность введения в программу ошибок, связанных с несовпадением типа данных у переменных.

В следующей таблице представлены префиксы переменных, которые в основном будут использоваться в этой книге:

Точка входа программы

Текст программы начинается с инструкции #include, которая позволяет включить в программу заголовочный файл WINDOWS.H:

#include <windows.h>

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

За инструкцией #include следует объявление WndProc.

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

Это объявление в начале программы необходимо потому, что в тексте функции WinMain имеются ссылки на функцию WndProc.

В программе на языке С, написанной для традиционной среды, точкой входа является функция main. С этого места программа начинает выполняться. (Фактически функция main является точкой входа в ту часть программы, которая пишется программистом. Обычно компилятор С должен вставить некоторый стартовый код в исполняемый файл. Этот код и вызывает функцию main.) Точкой входа программы для Windows является функция WinMain. WinMain всегда определяется следующим образом:

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)

Эта функция использует последовательность вызовов WINAPI и, по своему завершению, возвращает операционной системе Windows целое. Функция называется WinMain. В ней есть четыре параметра.

Параметр hInstance называется описателем экземпляра (instance handle). Это уникальное число, идентифицирующее программу, когда она работает под Windows. Может так случиться, что пользователь запустит под Windows несколько копий одной и той же программы. Каждая копия называется "экземпляром" и у каждой свое значение hInstance. Описатель экземпляра можно сравнить с "идентификатором задачи" или "идентификатором процесса" — обычными терминами многозадачных операционных систем.

Параметр hPrevInstance — предыдущий экземпляр (previous instance) — в настоящее время устарел. В ранних версиях Windows он относился к самому последнему, предшествующему данному, описателю экземпляра той программы, которая все еще активна. Если в данный момент времени не было загружено никаких копий программы, то hPrevInstance — 0 или NULL. Под Windows этот параметр всегда равен NULL.

Параметр szCmdLine — это указатель на оканчивающуюся нулем строку, в которой содержатся любые параметры, переданные в программу из командной строки. Вы можете запустить программу для Windows с параметром командной строки, вставив этот параметр после имени программы в командной строке MS-DOS или указать имя программы и параметр в окне диалога Run, которое вызывается из меню Start.

Параметр iCmdShow — число, показывающее, каким должно быть выведено на экран окно в начальный момент. Это число задается при запуске программы другой программой. Программисты достаточно редко обращаются к этому числу, но при необходимости такая возможность существует. В большинстве случаев число равно 1 или 7. Но лучше не думать об этом значении как о единице или как о семерке. Лучше думайте о них как об идентификаторе SW_SHOWNORMAL (заданном в заголовочных файлах Windows равным 1) или идентификаторе SW_SHOWMINNOACTIVE (заданном равным 7). Префикс SW в этих идентификаторах означает "показать окно" (show window). Параметр показывает, необходимо ли запущенную пользователем программу выводить на экран в виде окна нормального размера или окно должно быть изначально свернутым.

Регистрация класса окна

Окно всегда создается на основе класса окна. Класс окна идентифицирует оконную процедуру, которая выполняет процесс обработки сообщений, поступающих окну. Поскольку это важно, повторяем: окно всегда создается на основе класса окна. Класс окна идентифицирует оконную процедуру, которая выполняет процесс обработки сообщений, поступающих окну. На основе одного класса окна можно создать несколько окон. Например, все окна-кнопки в Windows создаются на основе одного и того же класса окна. Класс окна определяет оконную процедуру и некоторые другие характеристики окон, создаваемых на основе этого класса. Когда вы создаете окно, вы определяете дополнительные характеристики окна, уникальные для него.

Перед созданием окна для вашей программы необходимо зарегистрировать класс окна путем вызова функции RegisterClassEx. Это расширенная (на что указывает окончание названия Ех, т. е. extended — расширенный) версия функции RegisterClass из предыдущих версий Windows. Тем не менее функция RegisterClass продолжает работать и под Windows. У функции RegisterClassEx имеется один параметр: указатель на структуру типа WNDCLASSEX. Структура WNDCLASSEX определяется в заголовочных файла Windows следующим образом:

typedef struct tagWNDCLASSEX

{

UINT cbSize;

UINT style;

WNDPROC lpfnWndProc;

int cbClsExtra;

int cbWndExtra;

HINSTANCE hInstance;

HICON hIcon;

HCURSOR hCursor;

HBRUSH hbrBackground;

LPCSTR lpszMenuName;

LPCSTR lpszClassName;

HICON hlconSm;

} WNDCLASSEX;

Обратите также внимание на некоторые новые случаи использования венгерской нотации: приставка lpfn означает "длинный указатель на функцию" (long pointer to a function). Приставка cb означает "счетчик байтов" (counter of bytes). Префикс hbr — это "описатель кисти" (handle to a brush).

В WinMain вы должны определить структуру типа WNDCLASSEX, обычно это делается следующим образом:

WNDCLASSEX wndclass;

Затем задаются 12 полей структуры и вызывается RegisterClassEx:

RegisterClassEx(&wndclass);

Наиболее важными являются второе от конца и третье поля. Второе от конца поле является именем класса окна (который в программах, создающих одно окно, обычно совпадает с именем программы). Третье поле (lpfnWndProc) является адресом оконной процедуры, которая используется для всех окон, созданных на основе этого класса (в HELLOWIN. С оконной процедурой является функция WndProc). Другие поля описывают характеристики всех окон, создаваемых на основе этого класса окна.

Поле cbSize равно длине структуры. Инструкция:

wndclass.style = CS_HREDRAW | CS_VREDRAW;

осуществляет объединение двух идентификаторов "стиля класса" (class style) с помощью поразрядной операции OR языка С.

Эти два идентификатора стиля класса показывают, что все окна, созданные на основе данного класса должны целиком перерисовываться при изменении горизонтального (CS_HREDRAW) или вертикального (CS_VREDRAW) размеров окна. Если вы измените размер окна HELLOWIN, то увидите, что строка текста переместится в новый центр окна. Эти два идентификатора гарантируют, что это случится. Далее мы подробно рассмотрим, как оконная процедура уведомляется об изменении размера окна.

Третье поле структуры WNDCLASSEX инициализируется с помощью инструкции:

wndclass.lpfnWndProc = WndProc;

Эта инструкция устанавливает оконную WndProc как оконную процедуру данного окна, которая является второй функцией в HELLOWIN. С. Эта оконная процедура будет обрабатывать все сообщения всем окнам, созданным на основе данного класса окна. Как уже упоминалось, приставка lpfn означает "длинный указатель на функцию".

Следующие две инструкции:

wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0;

резервируют некоторое дополнительное пространство в структуре класса и структуре окна, которое внутренне поддерживается операционной системой Windows. Программа может использовать это свободное пространство для своих нужд. В HELLOWIN эта возможность не используется, поэтому соответствующие значения равны 0. В противном случае, как следует из венгерской нотации, в этом поле было бы установлено "число байтов" резервируемой памяти.

В следующем поле находится просто описатель экземпляра программы (который является одним из параметров WinMain:

wndclass.hInstance = hInstance;

Инструкции:

wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);

И

wndclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);

устанавливают значок для всех окон, созданных на основе данного класса окна. Значок — это просто маленькая битовая картинка, которая появляется на панели задач Windows и слева в заголовке окна. Позже из этой книги вы узнаете, как создавать пользовательские значки для ваших программ под Windows. Сейчас для простоты воспользуемся стандартным значком.

Для получения описателя стандартного значка, вы вызываете LoadIcon, установив первый параметр в NULL. (При загрузке вашего собственного пользовательского значка, этот параметр должен быть установлен равным описателю экземпляра программы.) Второй идентификатор, начинающийся с префикса IDI ("идентификатор для значка" — ID for icon) определяется в заголовочных файлах Windows. Значок IDI_APPLICATION — это просто маленькое изображение окна. Функция LoadIcon возвращает описатель этого значка. Фактически нам не важно конкретное значение этого описателя. Оно просто используется для установки значений полей wndclass.hIcon и wndclass.hIconSm. Эти поля определяются в структуре WNDCLASSEX как поля типа HICON, что означает "описатель значка" (handle to an icon).

Инструкция:

wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);

очень похожа на две предыдущие инструкции. Функция LoadCursor загружает стандартный курсор IDC_ARROW и возвращает описатель курсора. Этот описатель присваивается полю hCursor структуры WNDCLASSEX. Когда курсор мыши оказывается в рабочей области окна, созданного на основе данного класса, он превращается в маленькую стрелку.

Следующее поле задает цвет фона рабочей области окон, созданных на основе данного класса. Префикс hbr имени поля hbrBackground означает "описатель кисти" (handle to a brush). Кисть — это графический объект, который представляет собой шаблон пикселей различных цветов, используемый для закрашивания области. В Windows имеется несколько стандартных, или предопределенных (stock) кистей. Вызов GetStockObject, показанный здесь, возвращает описатель белой кисти:

wndclass.hbrBackground = GetStockObject(WHITE_BRUSH);

Это означает, что фон рабочей области окна будет плотного белого цвета, что является стандартным выбором.

Следующее поле задает меню класса окна. В приложении HELLOWIN меню отсутствует, поэтому поле установлено в NULL:

wndclass.lpszMenuName .= NULL;

На последнем этапе классу должно быть присвоено имя. Для простой программы оно может быть просто именем программы, которым в нашем случае является строка "HelloWin", хранящаяся в переменной szAppName:

wndclass.lpszClassName = szAppName;

После того как инициализированы все 12 полей структуры, HELLOWIN регистрирует класс окна путем вызова функции RegisterClassEx. Единственным параметром функции является указатель на структуру WNDCLASSEX:

RegisterClassEx(&wndclass);

Создание окна

Класс окна определяет основные характеристики окна, что позволяет использовать один и тот же класс для создания множества различных окон. Когда вы, вызывая функцию CreateWindow, фактически создаете окно, вы, таким образом, детализируете информацию об окне.

Вместо использования структуры данных, как это делается в случае использования функции RegisterClassEx, вызов функции CreateWindow требует, чтобы вся информация передавалась функции в качестве параметров. Далее представлен вызов функции CreateWindow в HELLOWIN.C:

hwnd = CreateWindow (szAppName, //имя класса окна

"The Hello Program", //заголовок окна

WS_OVERLAPPEDWINDOW, //стиль окна

CW_USEDEFAULT, //начальное положение по х

CW_USEDEFAULT, //начальное положение по у

CW_USEDEFAULT, //начальный размер по х

CW_USEDEFAULT, //начальный размер по у

NULL, //описатель родительского окна

NULL, //описатель меню окна

hInstance, //описатель экземпляра программы

NULL); //параметры создания

Для удобства восприятия, использовались символ // и однострочные комментарии для описания параметров функции CreateWindow.

Параметр с комментарием "имя класса окна" — szAppName содержит строку "HelloWin", являющуюся именем только что зарегистрированного класса окна. Таким образом, этот параметр связывает окно с классом окна.

Окно, созданное нашей программой, является обычным перекрывающимся окном с заголовком, системным меню слева на строке заголовка, иконками для сворачивания, разворачивания и закрытия окна справа на строке заголовка и рамкой окна. Это стандартный стиль окон, он называется WS_OVERLAPPEDWINDOW и помечен комментарием "стиль окна". Комментарием "заголовок окна" отмечен текст, который появится в строке заголовка.

Параметры с комментариями "начальное положение по х" и "начальное положение по У задают начальные координаты верхнего левого угла окна относительно левого верхнего угла экрана. Устанавливая для этих параметров идентификатор CW_USEDEFAULT, мы сообщаем Windows, что хотим использовать для перекрывающегося окна задаваемое по умолчанию начальное положение. По умолчанию Windows располагает следующие друг за другом перекрывающиеся окна, равномерно отступая по горизонтали и вертикали от верхнего левого угла экрана. Примерно также задают ширину и высоту окна параметры с комментариями "начальный размер по х" и "начальный размер по у". CW_USEDEFAULT снова означает, что мы хотим, чтобы Windows использовала задаваемый по умолчанию размер окна.

Параметр с комментарием "описатель родительского окна" устанавливается в NULL, поскольку у нашего окна отсутствует родительское окно. (Если между двумя окнами существует связь типа родительское-дочернее, дочернее окно всегда появляется только на поверхности родительского.) Параметр с комментарием "описатель меню окна" также установлен в NULL, поскольку у нашего окна нет меню. В параметр с комментарием "описатель экземпляра программы" помещается описатель экземпляра, переданный программе в качестве параметра функции WinMain. И наконец, параметр с комментарием "параметры создания" установлен в NULL. При необходимости этот параметр используется в качестве указателя на какие-нибудь данные, на которые программа в дальнейшем могла бы ссылаться.

Вызов Create Window возвращает описатель созданного окна. Этот описатель хранится в переменной hwnd, которая имеет тип HWND (описатель окна — handle to a window). У каждого окна в Windows имеется описатель. В вашей программе описатель используется для того, чтобы ссылаться на окно. Для многих функций Windows в качестве параметра требуется hwnd, благодаря этому Windows знает, к какому окну применить функцию. Если программа создает несколько окон, то каждое из них имеет свой описатель. Описатель окна — это один из важнейших описателей, которыми оперирует программа для Windows.

Отображение окна

К тому времени, когда функция CreateWindow возвращает управление программе, окно уже создано внутри Windows. Однако, на экране монитора оно еще не появилось. Необходимы еще два вызова. Первый из них:

ShowWindow(hwnd, iCmdShow);

Первым параметром является описатель только что созданного функцией CreateWindow окна. Вторым параметром является величина iCmdShow, передаваемая в качестве параметра функции WinMain. Он задает начальный вид окна на экране. Если iCmdShow имеет значение SW_SHOWNORMAL (т. е. 1), на экран выводится обычное окно. Если iCmdShow имеет значение SW_SHOWMINNOACTIVE (т. е. 7), то окно не выводится, а на панели задач появляются его имя и иконка.

Функция ShowWindow выводит окно на экран. Если второй параметр ShowWindow имеет значение SW_SHOWNORMAL, то фон рабочей области окна закрашивается той кистью, которая задана в классе окна. Вызов функции:

UpdateWindow (hwnd);

вызывает затем перерисовку рабочей области. Для этого в оконную процедуру (функция WndProc в HELLOWIN.C) посылается сообщение WM_PAINT.

Цикл обработки сообщений

После вызова функции Update Window, окно окончательно выведено на экран. Теперь программа должна подготовить себя для получения информации от пользователя через клавиатуру и мышь. Windows поддерживает "очередь сообщений" (message queue) для каждой программы, работающей в данный момент в системе Windows. Когда происходит ввод информации, Windows преобразует ее в "сообщение", которое помещается в очередь сообщений программы.

Программа извлекает сообщения из очереди сообщений, выполняя блок команд, известный как "цикл обработки сообщений" (message loop):

While (GetMessage(&msg, NULL, 0, 0))

{

TranslateMessage(&msg);

DispatchMessage(&msg);

}

return msg.wParam;

Переменная msg — это структура типа MSG, которая определяется в заголовочных файлах Windows следующим образом:

typedef struct tagMSG

{

HWND hwnd;

UINT message;

WPARAM wParam;

LPARAM IParam;

DWORD time;

POINT pt;

} MSG;

Тип данных POINT — это тип данных другой структуры, которая определяется так:

typedef struct tagPOINT

{

LONG x;

LONG y;

} POINT;

Вызов функции GetMessage, с которого начинается цикл обработки сообщений, извлекает сообщение из очереди сообщений:

GetMessage (&msg, NULL, 0, 0)

Этот вызов передает Windows указатель на структуру msg типа MSG. Второй, третий и четвертый параметры, NULL или 0, показывают, что программа получает все сообщения от всех окон, созданных этой программой. Windows заполняет поля структуры сообщений информацией об очередном сообщении из очереди сообщений. Поля этой структуры следующие:

hwnd — описатель окна, для которого предназначено сообщение. В программе HELLOWIN, он тот же, что и hwnd, являющийся возвращаемым значением функции CreateWindow, поскольку у нашей программы имеется только одно окно.

message — идентификатор сообщения. Это число, которое идентифицирует сообщение. Для каждого сообщения имеется соответствующий ему идентификатор, который задается в заголовочных файлах Windows и начинается с префикса WM (оконное сообщение — window message).

wParam — 32-разрядный параметр сообщения (message parameter), смысл и значение которого зависят от особенностей сообщения.

lParат — другой 32-разрядный параметр, зависящий от сообщения.

time — время, когда сообщение было помещено в очередь сообщений.

pt — координаты курсора мыши в момент помещения сообщения в очередь сообщений.

Если поле message сообщения, извлеченного из очереди сообщений, равно любому значению, кроме WM_QUIT, то функция GetMessage возвращает ненулевое значение. Сообщение WM_QUIT заставляет программу прервать цикл обработки сообщений. На этом программа заканчивается, возвращая число wParam структуры msg.

Инструкция:

TranslateMessage(&msg);

передает структуру msg обратно в Windows для преобразования какого-либо сообщения с клавиатуры.

Инструкция:

DispatchMessage(&msg);

также передает структуру msg обратно в Windows. Windows отправляет сообщение для его обработки соответствующей оконной процедуре — таким образом, Windows вызывает оконную процедуру. Такой оконной процедурой hellowin является функция WndProc. После того, как WndProc обработает сообщение, оно возвращается в Windows, которая все еще обслуживает вызов функции DispatchMessage. Когда Windows возвращает управление в программу HELLOWIN к следующему за вызовом DispatchMessage коду, цикл обработки сообщений в очередной раз возобновляет работу, вызывая GetMessage.

Оконная процедура

Обо всем, о чем так долго говорилось, можно кратко сказать так: класс окна зарегистрирован, окно создано, окно выведено на экран, и для извлечения сообщений из очереди сообщений программа вошла в цикл обработки сообщений.

Реальная работа начинается в оконной процедуре, которую программисты обычно называют "window proc". Оконная процедура определяет то, что выводится в рабочую область окна и то, как окну реагировать на пользовательский ввод.

В программе HELLOWIN оконной процедурой является функция WndProc. Оконной процедуре можно назначить любое имя (любое, конечно, в той степени, в которой оно не будет конфликтовать с другими именами). В программе для Windows может содержаться более одной оконной процедуры. Оконная процедура всегда связана с определенным классом окна, который вы регистрируете, вызывая RegisterClassEx. Функция CreateWindow создает окно на основе определенного класса окна. На основе одного и того же класса можно создать несколько окон.

Оконная процедура всегда определяется следующим образом:

LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)

Отметьте, что четыре параметра оконной процедуры идентичны первым четырем полям структуры MSG.

Первым параметром является hwnd, описатель получающего сообщение окна. Это тот же описатель, который возвращает функция CreateWindow. Для программы типа HELLOWIN, в которой создается только одно окно, имеется только один известный программе описатель окна. Если же в программе создается несколько окон на основе одного и того же класса окна (и следовательно одной и той же оконной процедуры), тогда hwnd идентифицирует конкретное окно, которое получает сообщение.

Вторым параметром является число (точнее 32-разрядное беззнаковое целое или UINT), которое идентифицирует сообщение. Два последних параметра (wParam типа WPARAM и lParam LPARAM) представляют дополнительную информацию о сообщении. Они называются "параметрами сообщения" (message parameters). Конкретное значение этих параметров определяется типом сообщения.

Обработка сообщений

Каждое получаемое окном сообщение идентифицируется номером, который содержится в параметре iMsg оконной процедуры. В заголовочных файлах Windows определены идентификаторы, начинающиеся с префикса WM ("window message") для каждого типа сообщений.

Обычно программисты для Windows используют конструкции switch и case для определения того, какое сообщение получила оконная процедура и то, как его обрабатывать. Если оконная процедура обрабатывает сообщение, то ее возвращаемым значением должен быть 0. Все сообщения, не обрабатываемые оконной процедурой, должны передаваться функции Windows, которая называется DefWindowProc. Значение, возвращаемое функцией DefWindowProc, должно быть возвращаемым значением оконной процедуры.

В HELLOWIN функция WndProc обрабатывает только три сообщения: WM_CREATE, WM_PAINT и WM_DESTROY. Оконная процедура выглядит следующим образом:

switch (iMsg)

{

case WM_CREATE:

[process WM_CREATE message]

 return 0;

case WM_PAINT:

[process NM_PAINT message]

return 0;

case WM_DESTROY:

[process WM_DESTROY message]

return 0;

} return DefWindowProc (hwnd, iMsg, wParam, lParam) ;

Здесь важно отметить то, что вызов функции DefWindowProc обрабатывает по умолчанию все сообщения, которые не обрабатывает ваша оконная процедура.

Сообщение WM_CREATE

Самое первое сообщение, которое получает оконная процедура — и первое, которое обрабатывает функция WndProc — это WM_CREATE. WndProc получает это сообщение тогда, когда Windows обрабатывает функцию CreateWindow в WinMain. Таким образом, когда HELLOWIN вызывает CreateWindow, Windows делает то, что должна делать, т. е. Windows вызывает WndProc с описателем окна в качестве первого параметра и с WM_CREATE в качестве второго. WndProc обрабатывает сообщение WM_CREATE и передает управление обратно в Windows. Теперь Windows может вернуться после вызова CreateWindow обратно в HELLOWIN, чтобы продолжить работу в WinMain.

Часто оконная процедура выполняет разовую инициализацию окна, когда обрабатывается сообщение. WM_CREATE. HELLOWIN предпочитает обрабатывать это сообщение путем воспроизведения звукового файла HELLOWIN.WAV. Это делается с помощью функции PlaySound. Первым параметром этой функции является имя файла. Это также может быть другое имя (sound alias name), которое задается в секции Sounds панели управления (Control Panel) или определяется ресурсом программы. Второй параметр используется только при условии, что звуковой файл является ресурсом. Третий параметр задает две опции. В нашем случае, когда первый параметр — это имя файла, звук должен воспроизводиться асинхронно, т. е. функция PlaySound возвратит свое значение как только начнет воспроизводиться звуковой файл, не ожидая окончания воспроизведения.

WndProc завершает обработку WM_CREATE с нулевым возвращаемым значением.

Сообщение WM_PAINT

Сообщение WM_PAINT функция WndProc обрабатывает вторым. Это сообщение крайне важно для программирования под Windows. Оно сообщает программе, что часть или вся рабочая область окна недействительна (invalid), и ее следует перерисовать.

Как рабочая область становится недействительной? При первом создании окна недействительна вся рабочая зона, поскольку программа еще ничего в окне не нарисовала. Сообщение WM_PAINT (которое обычно посылается, когда программа вызывает UpdateWindow в WinMaini) заставляет оконную процедуру что-то нарисовать в рабочей области.

Когда вы изменяете размер окна, рабочая область также становится недействительной. Вспомните, что в параметр style структуры wndclass программы HELLOWIN помещены флаги CS_HREDRAW и CS_VREDRAW. Они заставляют Windows при изменении размеров окна считать недействительным все окно. Затем оконная процедура получает сообщение WM_PAINT. Когда вы минимизируете окно программы HELLOWIN, а затем снова его восстанавливаете до начального размера, то в Windows содержимое рабочей области не сохраняется. В графической среде это привело бы к тому, что пришлось бы хранить слишком много данных. Вместо этого, Windows делает недействительным все окно. Оконная процедура получает сообщение WM_PAINT и сама восстанавливает содержимое окна. Когда вы перемещаете окна так, что они перекрываются, Windows не сохраняет ту часть окна, которая закрывается другим окном. Когда эта часть окна позже открывается, Windows помечает его как недействительное. Оконная процедура получает сообщение WM_PAINT для восстановления содержимого окна.

Обработка сообщения WM_PAINT почти всегда начинается с вызова функции BeginPaint.

hdc = BeginPaint (hwnd, &ps);

и заканчивается вызовом функции EndPaint.

EndPaint (hwnd, &ps) ;

В обеих функциях первый параметр — это описатель окна программы, а второй — это указатель на структуру типа PAINTSTRUCT. В структуре PAINTSTRUGT содержится некоторая информация, которую оконная процедура может использовать для рисования в рабочей области.

При обработке вызова BeginPaint, Windows обновляет фон рабочей области, если он еще не обновлен. Обновление фона осуществляется с помощью кисти, заданной в поле hbrBackground структуры WNDCLASSEX, которая использовалась при регистрации класса окна. В случае нашей программы HELLOWIN подготовлена белая кисть и это означает, что Windows обновит фон окна, закрасив его белым цветом. Вызов BeginPaint делает всю рабочую область действительной (не требующей перерисовки) и возвращает описатель контекста устройства. Контекст устройства описывает физическое устройство вывода информации (например, дисплей) и его драйвер. Описатель контекста устройства необходим вам для вывода в рабочую область окна текста и графики. Используя описатель контекста устройства, возвращаемого функцией BeginPaint, вы не сможете рисовать вне рабочей области, даже не пытайтесь. Функция EndPaint освобождает описатель контекста устройства, после чего его значение нельзя использовать.

Если оконная процедура не обрабатывает сообщения WM_PAINT (что бывает крайне редко), они должны передаваться в DefWindowProc. Функция DifWindowProc просто по очереди вызывает BeginPaint и EndPaint и, таким образом, рабочая область устанавливается в действительное состояние, т. е. состояние, не требующее перерисовки.

После того, как WndProc вызвала BeginPaint, она вызывает GetClientRect

GetClientRect (hwnd, &rect) ;

Первый параметр — это описатель окна программы. Второй параметр — это указатель на переменную rect, для которой в WndProc задан тип RECT.

RECT — это структура "прямоугольник" (rectangle), определенная в заголовочных файлах Windows. Она имеет четыре поля типа LONG, имена полей: left, top, right и bottom. GetClientRect помещает в эти четыре поля размер рабочей области окна. Поля left и top всегда устанавливаются в 0. В полях right и bottom устанавливается ширина и высота рабочей области в пикселях.

WndProc никак не использует структуру RECT, за исключением передачи указателя на нее в качестве четвертого параметра функции DrawText.

DrawText(hdc, "Hello, Windows!", -1, &rect, DT_SINGLELINE|DT_CENTER|DT_VCENTER);

DrawText (как подсказывает ее имя) рисует текст. Поскольку эта функция что-то рисует, то первый параметр — это описатель контекста устройства, возвращенный функцией BeginPaint. Вторым параметром является рисуемый текст, а третий параметр установлен в — 1, чтобы показать, что строка текста заканчивается нулевым символом.

Последний параметр — это набор флагов, значения которых задано в заголовочных файлах Windows. Флаги показывают, что текст следует выводить в одну строку, по центру относительно горизонтали и вертикали и внутри прямоугольной области, размер которой задан четвертым параметром. Вызов этой функции приводит, таким образом, к появлению строки "Hello, Windows!" в центре рабочей области.

Когда рабочая область становится недействительной (как это происходит при изменении размеров окна), WndProc получает новое сообщение WM_PAINT. Новый размер окна WndProc получает, вызвав функцию GetClientRect, и снова рисует текст в центре окна.

Сообщение WM_DESTROY

Еще одним важным сообщением является сообщение WM_DESTROY. Это сообщение показывает, что Windows находится в процессе ликвидации окна в ответ на полученную от пользователя команду. Пользователь вызывает поступление этого сообщения, если щелкнет на кнопке Close, или выберет Close из системного меню программы, или нажмет <Alt>+<F4>.

HELLOWIN стандартно реагирует на это сообщение, вызывая:

PostQuitMessage(O);

Эта функция ставит сообщение WM_QUIT в очередь сообщений программы. Как уже упоминалось, функция GetMessage возвращает ненулевое значение при любом сообщении, полученном из очереди сообщений за исключением WM_QUIT. Когда GetMessage получает сообщение WM_QUIT, функция возвращает 0. Это заставляет WinMain прервать цикл обработки сообщений и выйти в систему, закончив программу.


Дата добавления: 2018-02-28; просмотров: 396; Мы поможем в написании вашей работы!

Поделиться с друзьями:






Мы поможем в написании ваших работ!