LRESULT CALLBACK WndProc (
HWND hwnd, //дескриптор окна
UINT message, //номер сообщения;
WPARAM wParam, // дополнительная информация о сообщении
LPARAM IParam); // дополнительная информация о сообщении
В поле message записан код сообщения (нажата кнопка мыши, изменился размер окна, сделана выборка из меню и так далее). Поля wParam и IParam дают дополнительную информацию. Например, если изменились размеры окна, то эти параметры содержат новые размеры.
Модификатор САLLBACK yкaзывает на соглашение о передаче параметров _pascal
#define CALLBACK _pascal
Оконная процедура должна уметь обрабатывать все сообщения, но в Windows таких сообщений десятки тысяч. Всё сводиться к тому, что ваша оконная процедура будет обрабатывать только необходимые для вас сообщения, а всё остальные сообщения будет обрабатывать оконная процедура по умолчанию - DefWindowProc();
/* Пример оконной процедуры */ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch(msg) { case WM_DESTROY: // поставить сообщение WM_QUIT в очередь сообщений PostQuitMessage(0); break; default: // оконная процедура по умолчанию return DefWindowProc(hWnd,msg,wParam,lParam); } return 0; } |
Эта оконная процедура обрабатывает только одно сообщение - WM_DESTROY, все остальные сообщения обрабатывает оконная процедура по умолчанию.
Замечание. Сообщение WM_DESTROY посылается окну, когда пользователь пытается закрыть окно.
Оконная процедура обрабатывает сообщения для окон определённого класса.
После заполнения структуры WNDCLASSEX, класс необходимо зарегистрировать в системе. Это делается с помощью функции RegisterClassEx();
Переменная aWndClass используется для временного хранения кода возврата функции RegisterClass. Эта функция относится к функциям программного интерфейса Windows, она и выполняет регистрацию класса окна. В качестве единственного параметра функции необходимо указав адрес предварительно проинсталлированной структуры типаWNDCLASS:
aWndClass = RegisterClass( &wc );
Прототип функции RegisterClass:
ATOM WINAPI RegisterClass ( &wc );
To есть процедура регистрации класса окна несложна.
ATOM - переменная специального типа. В файле windows.h переменнаяATOM определяется следующим образом:
typedef UINT ATOM;
typedef unsigned int UINT;
WNDCLASSEX wc;
// Заполняем структуру WNDCLASS
// ....
// Регистрируем новый класс
RegisterClassEx(&wc);
Теперь, когда наш класс зарегистрирован в системе, мы можем создавать окна нашего класса.
Создание окна
Создание окна производиться с помощью функции CreateWindow() или CreateWindowEx().
В случае успеха функция CreateWindow() возвращает хэндл нового созданного окна, иначе функция возвращает NULL.
HWND CreateWindow( LPCTSTR lpClassName, LPCTSTR lpWindowName, DWORD dwStyle, int x, int y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HANDLE hInstance, LPVOID lpParam ); |
- lpClassName - имя зарегистрированного класса окна;
- lpWindowName - заголовок окна;
- dwStyle - стиль окна (комбинация флагов);
- x - начальное положение по X;
- y - начальное положение по Y;
- nWidth - ширина окна;
- nHeight - высота окна;
- hWndParent - хэндл окна родителя;
- hMenu - хэндл меню окна;
- hInstance - хэндл экземпляра приложения, создающий окно;
- lpParam - указатель на параметры для WM_CREATE.
После создания окна его необходимо отобразить на экране. Чтобы окно было показано на экране необходимо вызвать функцию ShowWindow().
ShowWindow(hWnd, SW_SHOW);
1. Функция WinMain после инициализации и создания окна входит в цикл обработки сообщений, после выхода из которого приложение завершает работу.
2. Функция окна WndProc вообще не вызывается ни из какой другой функции приложения, хотя именно она выполняет всю работу!
Работа приложения Windows отличается от работы программы DOS. При определении классов окон, указываются адреса функций окон, и только после этого создаются сами окна. После создания окна функциейCreateWindow окно на экране монитора не появиться. В этом можно убедиться воспользовавшись отладчиком. Нарисовать окно на экране можно с помощью функции ShowWindow.
Прототип функции:
BOOL ShowWindow (
HWND hwnd,
int nCmdShow );
Функция отображает окно, дескриптор которого задан параметром hwnd. Наше приложение использует в качестве второго параметра, значение nCmdShow, передаваемое Windows функции WinMain. Сразу после функции ShowWindow вызывается функция UpdateWindow.
Прототип функции:
void UpdateWindow (
HWND hwnd II дескриптор окна
);
Эта функция передает окну, заданному дескриптором hwnd, сообщение WM_PAINT. Получив это сообщение из частной очереди сообщений, окно перерисовывает свою клиентскую область. В нашем случае вызов этой функции пока не имеет смысла. Она включена для общности.
При запуске вашего приложения, Windows создаёт для него очередь сообщений. Очередь сообщений создаётся для каждого потока (thread), но в самом простейшем случае создаётся одна очередь.
При любом действии с окном (изменение размеров и т.д.) Windows помещает в очередь соответствующее сообщение. Формат сообщения соответствует структуре MSG.
Приложение само обслуживает свою частную очередь сообщений. Это осуществляется в цикле. Обнаружив сообщение, с помощью специальной функцииGetMessage, приложение с помощью другой специальной функцииDispatchMessage распределяет его нужной функции окна, которая и выполняет обработку сообщения. После обработки сообщения приложение вновь возвращается к опросу собственной очереди.
Windows - мультизадачная OS, поэтому в ней предусмотрен механизм совместного использования таких ресурсов, как мышь и клавиатура. Так как все сообщения попадают в первичную входную очередь, должен существовать способ распределения этих сообщений между различными приложениями. В Windows существует понятие фокуса ввода (input focus), помогающее распределять сообщения.
Фокус ввода, в любой момент времени может принадлежать только одному окну. Если окно имеет фокус ввода, то все клавиатурные сообщения попадают из системной очереди в окно владеющего фокусом ввода. Нажимая определенные клавиши (например Tab) можно перемещать фокус ввода между окнами. Если эти окна являются кнопками, то окно (кнопка) имеющее фокус ввода помечается пунктиром.
Сообщение от мыши всегда передаются тому окну, над которым находиться курсор мыши.
Простейший вариант цикла обработки сообщений выглядит так:
MSG msg;
while (GetMessage (&msg, 0, 0, 0))
{
DispatchMessage ( &msg);
}
Функция GetMessage служит для приема сообщений msg (message)из частных очередей сообщений. Функция DispatchMessage распределяет сообщения между окнами приложения. Этих окон может быть много, в том числе и различные кнопки, которые, как мы уже отмечали, представляют собой ни что иное, как окна.
Завершается цикл обработки сообщений при выборке из очереди специального сообщения, означающего завершение работы пользователя с приложением, в ответ, на которое функция GetMessage возвращает нуль. Процесс обработки сообщений выглядит так, как показано на рис. 4,1 :
Перед завершением обработки сообщенияWM_PAINT приложение должно обязательно вызвать функцию EndPaint, освобождающую полученный ранее контекст отображения устройства:
Типы сообщений
Существует много разновидностей сообщений, представляющих события на разных уровнях. Каждое простое событие, каждое простое действие посылается в виде сообщения окну для обработки.
Приложению приходит множество сообщений, однако приложение не должно заботиться о смысле каждого отдельного сообщения. Вместо обработки всех возможных сообщений приложение имеет свободу выбора; необработанные сообщения передаются в функции обработки сообщений операционной системы по умолчанию.
Приходящее приложению Windows-сообщение состоит из нескольких частей, для его представления используется структура MSG.Приведем описаниеструктуры, применяющейся для представления сообщения, т.е. описывающей тип сообщения:
typedef struct tagMSG { HWND hwnd; // окно, которому посылается это сообщение UINT message; // значение самого сообщение WPARAM wParam; // для передачи дополнительной информации LPARAM lParam; // для передачи дополнительной информации DWORD time; // время, когда произошло событие POINT pt; // точка, где произошло события (для мыши) } MSG;Элемент структуры hwnd однозначно идентифицирует окно, которому посылается это сообщение. Каждое окно в Windows имеет такой идентификатор. Элемент message идентифицирует само сообщение. Этот элемент может иметь сотни различных значений, означающих одно из многих сотен различных сообщений, которые могут получать приложения Windows.
Для идентификаторов сообщений обычно используются символьные представления (WM_PAINT, WM_TIMER), а не числовые значения. Эти символьные значения определены в стандартных файлах заголовков Windows (приложению необходимо включать в свой исходный текст только файл windows.h – он содержит директивы #include для остальных файлов).
Сообщения можно разделить на несколько групп в зависимости от их функций. Самой насыщенной группой сообщений является группа сообщений управления окнами. Символьные идентификаторы для этих сообщений начинаются с WM_.Эта группа настолько велика, что ее уместно еще раз разбить на категории. Эти категории включают:
- сообщения DDE (dynamic data exchange),
- сообщения буфера обмена (clipboard),
- сообщения мыши,
- сообщения клавиатуры,
- сообщения неклиентской (non-client) области окна,
- сообщения MDI (multiple-document interface),
- и многие другие типы.
Перечисленные категории несколько неточны, не всегда строго определены; они просто служат для удобства программистов, чтобы можно было представить картину множества событий управления окнами. Множество сообщений WM_ также не фиксировано, оно растет по мере добавления новых возможностей операционной системы.
Другие группы сообщений связаны с определенными типами окон. Существуют сообщения, определенные для полей ввода, кнопок, списков, комбинированных списков, полос прокрутки, элементов просмотра списка деревьев и т.д. Эти сообщения за редким исключением обычно обрабатываются оконной процедурой окна элемента управления и редко представляют интерес для программистов приложений.
Дата добавления: 2017-01-26; просмотров: 3163;