Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
System programming / Конспект лекций / Лекция 2 Скелет программы.doc
Скачиваний:
55
Добавлен:
08.05.2015
Размер:
97.79 Кб
Скачать

Порядок обработки сообщений, цикл обработки сообщений

Когда в системе происходит какое-либо событие, на которое должна отреагировать исполняемая программа (например, нажата клавиша на клавиатуре, перемещена мышь или истекло время ожидания), операционная система посылает программе сообщение об этом событии. Программа получает сообщение и выполняет код (часть программы), реагирующий на это событие. На рис. 2.1. отображен этот процесс.

Рис. 2.1. Порядок прохождения сообщения

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

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

Стандартный цикл обработки сообщений имеет вид:

MSG msg;

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

{

TranslateMessage(&msg);

DispatchMessage(&msg);

}

Функция GetMessage выбирает очередное сообщение из программной очереди. Результатом выполнения функции является заполнение структуры msg, которая содержит всю необходимую информацию о полученном сообщении: описатель окна, которому предназначено сообщение, тип сообщения, параметры сообщения (зависящие от типа сообщения) и время возникновения сообщения. Функция также возвращает некоторое число, которое отлично от нуля для всех сообщений кроме сообщения о закрытии программы. В последнем случае цикл обработки сообщений прерывается и программа завершается.

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

Функция DispatchMessage определяет какому окну приложения послано сообщение и вызывает соответствующую оконную процедуру.

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

Оконная процедура является центральной частью программы. Не будет большим преувеличением сказать, что более девяносто процентов алгоритма программы заключено в оконной процедуре. Оконная процедура соответствует одному (или более) окну программы и содержит в себе программную реализацию поведения окна. Подпрограммы рисования элементов окна, реакция на действия мыши, клавиатуры, закрытия окна – все это заключено внутри оконной процедуры.

Оконная процедура имеет стандартный вид:

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)

{

. . . . .

switch (message)

{

case WM_CREATE: // Сообщение приходит при создании окна

. . . . . . .

break;

case WM_PAINT: // Перерисовать окно

. . . . . . .

break;

case WM_DESTROY: // Завершение работы

. . . . . . .

break;

default:

// Обработка сообщений, которые не обработаны пользователем

return DefWindowProc(hWnd, message, wParam, lParam);

}

return 0;

}

Оконная процедура вызывается только тогда, когда пришло какое-либо сообщение, предназначенное соответствующему окну. Обратите внимание, что оконная процедура задается в классе регистрации окна, то есть для нескольких окон существует только один экземпляр оконной процедуры. Какому именно окну послано сообщение определят первый параметр функции WndProc – описатель окна hWnd.

Второй параметр функции - message -определяет тип сообщения и принимает одно значение из множества WM_<сообщение>. Например, когда message равно WM_CREATE, это означает, что пришло сообщение о создании окна (данное сообщение является первым сообщением, приходящим в оконную процедуру после создания окна и приходит только один раз).

Третий и четвертый параметры - wParam и lParam сопутствуют сообщению и зависит от его типа. Например, если приходит сообщение о нажатии мыши, в этих параметрах содержится информация о координатах мыши в момент нажатия и состоянии управляющих клавиш.

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

В заключение лекции приведем полностью текст программы, которая является полноправным оконным приложением. В результате выполнения программы на экране появляется окно, содержащее стандартные элементы (заголовок, рамку, кнопки управления) и надпись "Первая программа для WINDOWS". Окно можно перемещать, минимизировать, максимизировать, свертывать. Можно также изменять его размеры с помощью мыши и наблюдать программу на панели задач.

#include <windows.h> // подключение библиотеки с функциями API

// Глобальные переменные:

HINSTANCE hInst; // Указатель приложения

// Предварительное описание функций

ATOM MyRegisterClass(HINSTANCE hInstance);

BOOL InitInstance(HINSTANCE, int);

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

// Основная программа

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine,

int nCmdShow)

{

MSG msg;

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

MyRegisterClass(hInstance);

// Создание окна приложения

if (!InitInstance (hInstance, nCmdShow))

{

return FALSE;

}

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

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

{

TranslateMessage(&msg);

DispatchMessage(&msg);

}

return msg.wParam;

}

// FUNCTION: MyRegisterClass()

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

ATOM MyRegisterClass(HINSTANCE hInstance)

{

WNDCLASSEX wcex;

wcex.cbSize = sizeof(WNDCLASSEX);

wcex.style = CS_HREDRAW | CS_VREDRAW; // стиль окна

wcex.lpfnWndProc = (WNDPROC)WndProc; // оконная процедура

wcex.cbClsExtra = 0;

wcex.cbWndExtra = 0;

wcex.hInstance = hInstance; // указатель приложения

wcex.hIcon = MyIcon1; // определение иконки

wcex.hCursor = LoadCursor(NULL, IDC_ARROW); // определение курсора

wcex.hbrBackground = GetSysColorBrush(COLOR_BTNFACE); // установка фона

wcex.lpszMenuName = NULL; // определение меню

wcex.lpszClassName = "MyClass"; // имя класса

wcex.hIconSm = NULL;

return RegisterClassEx(&wcex); // регистрация класса окна

}

// FUNCTION: InitInstance(HANDLE, int)

// Создает окно приложения и сохраняет указатель приложения в переменной hInst

BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)

{

HWND hWnd;

hInst = hInstance; // сохраняет указатель приложения в переменной hInst

hWnd=CreateWindow("MyClass", // имя класса окна

"My first program", // имя приложения

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

CW_USEDEFAULT, // положение по Х

CW_USEDEFAULT, // положение по Y

CW_USEDEFAULT, // размер по Х

CW_USEDEFAULT, // размер по Y

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

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

hInstance, // указатель приложения

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