Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Конспект лекций Часть II.doc
Скачиваний:
14
Добавлен:
20.11.2018
Размер:
1.48 Mб
Скачать

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

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

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

Всякий раз, когда приложение готово прочитать следующее сообщение, оно должно вызывать функцию API GetMessage. Она имеет следующий прототип:

BOOL GetMessage( LPMSG lpmsg, HWND hwnd,

WORD uMsgFilterMin, WORD uMsgFilterMax);

Параметр lpmsg указывает на структуру типа MSG, в которую будет за­писано выбираемое сообщение, hwnd - дескриптор окна, для которого нуж­но выбрать сообщение. Если hwnd=NULL, то выбираются сообщения для всех окон приложения. Параметры uMsgFilterMin и uMsgFilterMax указы­вают диапазон выбираемых сообщений, задавая соответственно мини­мальное и максимальное значение кодов сообщений. Если для этих па­раметров указать нулевые значения, из очереди будут выбираться все сообщения.

Функция GetMessage выбранное сообщение удаляет из очереди и за­писывает его в структуру, адрес которой задан ее первым параметром. При выборке сообщения с кодом WM_QUIT она возвращает 0, и завер­шается цикл обработки сообщений. При выборке других сообщений функция GetMessage возвращает ненулевое значение.

После этого функция WinMain возвращает управление и значение поля wParam последнего сообщения операционной системе.

Структура типа MSG описана следующим образом:

typedef struct

{ HWND hwnd; //Дескриптор окна-адресата

UINT message; //Код сообщения

WPARAM wParam; //Содержимое сообщения

LPARAM lParam; //Содержимое сообщения

DWORD time; //Время отправления

POINT pt; //Координаты места отправления

} MSG; //Имя типа

Цикл обработки сообщений имеет следующий вид:

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

{

TranslateMessage(&msg);

DispatchMesage(&msg);

}

Функция GetMessage заполняет поля структуры msg данными следующего сообщения из очереди. Вызов DispatchMesage вызывает соответствующую оконную процедуру. Между двумя этими функциями находится функция TranslateMessage.

Функция TranslateMessage преобразует аппаратные сообщения клавиатуры в символьные сообщения. Если этим сообщением является WM_KEYDOWN (WM_SYSKEYDOWN) и, если нажатие клавиши в сочетании с положением клавиши сдвига генерирует символ, тогда TranslateMessage помещает символьное сообщение в очередь сообщений.

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

П. 1.10 Структура текста приложения

Структура текста приложения определяется двумя требованиями:

1. Текст содержит описание функции с именем WinMain.

2. Если регистрируются новые классы, то текст содержит описание структуры типа WNDCLASS и функций окон этих классов.

Следующее приложение регистрирует класс перекрывающихся окон, создает окно этого класса и передает управление циклу обработки сообщений.

// Иллюстрация структуры простейшего приложения.

#include <windows.h>

//Описание прототипов функций

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

//Описание глобальных переменных

char Name[]="MainWindow";

HINSTANCE hinst;

int WINAPI WinMain(HINSTANCE hInstance,

HINSTANCE Prev,

LPSTR Line,

int Show)

{

MSG msg;

HWND hwnd;

hinst=hInstance;

//Описываем класс окна

WNDCLASS wc;

wc.style=wc.cbClsExtra=wc.cbWndExtra=0;

wc.lpfnWndProc=WndProc;

wc.hInstance=hinst;

wc.hIcon=LoadIcon(NULL,IDI_APPLICATION);

wc.hCursor=LoadCursor(NULL, IDC_ARROW);

wc.hbrBackground=(HBRUSH)(color+1);

wc.lpszMenuName=NULL;

wc.lpszClassName=Name;

wc.style=CS_HREDRAW | CS_VREDRAW;

//Регистрируем класс окна

if (RegisterClass(&wc)==0) return FALSE;

//Создаем окно класса Name

hwnd=CreateWindow(Name,"Каркас приложения для Windows",

WS_OVERLAPPEDWINDOW|WS_VISIBLE,

0,0,750,550,0, 0, hInstance, NULL);

if (!hwnd) return FALSE;

//Вызываем цикл обработки сообщений

while (GetMessage(&msg, 0, 0, 0)) DispatchMessage(&msg);

return msg.wParam;

}

//Описываем оконную функцию

LRESULT CALLBACK MainWindow(HWND hwnd, UINT msg,

WPARAM wParam, LPARAM lParam)

{

switch (msg)

{

case WM_DESTROY:

{PostQuitMessage(0); return (0);}

}

return DefWindowProc(hwnd, msg, wParam, lParam);

}

Как видно из листинга, приложение является обычной программой языка Си. Текст содержит привычные директивы, объявления и описа­ния. Отличие содержится в заголовке главной функции, в специфиче­ской функции окна и в способе ее вызова.

Рассмотрим алгоритм работы этого приложения.

1. Классы окон регистрируют в начале работы приложения.

2. Окно приложения создают до передачи управления циклу обработ­ки сообщений.

3. Управление передают циклу обработки сообщений. В теле этого цикла выбираются и распределяются сообщения.

4. Функция окна обрабатывает сообщение WM_DESTROY, а осталь­ные сообщения возвращает системе. Функция окна приложения долж­на обрабатывать это сообщение.

5. Приложение завершает работу.

Таким же является алгоритм работы большинства приложений. От­личие между ними в основном заключается в функциях окон.