Здавалка
Главная | Обратная связь

Посылка асинхронных сообщений



Сообщения ставятся в очередь асинхронных сообщений вызовом функции PostMessage (для посылки сообщения окну) или PostThreadMessage (для посылки сообщения потоку):

BOOL PostMessage(

HWND hWindow,

UINT message,

WPARAM wParam,

LPARAM lParam);

 

BOOL PostThreadMessage(

DWORD threadID,

UINT message,

WPARAM wParam,

LPARAM lParam);

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

Чтобы завершить цикл выборки сообщений потока, следует вызвать PostQuitMessage, передав в параметре exitCode код завершения:

VOID PostQuitMessage(int exitCode);

Посылка синхронных сообщений

Сообщение можно послать синхронно вызовом функции SendMessage:

LRESULT SendMessage(

HWND hWindow,

UINT message,

WPARAM wParam,

LPARAM lParam);

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

Если заранее неизвестно, как долго может продлиться обработка сообщения, или есть вероятность «зависания», можно воспользоваться функцией SendMessageTimeout, которая позволяет задавать максимальное время ожидания окончания обработки сообщения (timeout):

BOOL SendMessageTimeout(

HWND hWindow,

UINT message,

WPARAM wParam,

LPARAM lParam,

UINT flags,

UINT timeout,

PDWORD_PTR result);

Если же есть необходимо определить факт окончания обработки сообщения и в связи с этим выполнить какие-либо действия, то лучше всего для этой задачи подходит функция SendMessageCallback:

BOOL SendMessageCallback(

HWND hWindow,

UINT message,

WPARAM wParam,

LPARAM lParam,

SENDASYNCPROC resultCallBack,

ULONG_PTR data);

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

VOID ResultCallBack(HWND hWnd, UINT msg, ULONG_PTR data, LRESULT result);

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

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

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

Класс окна описывается структурой WNDCLASS или WNDCLASSEX. Поля этой структуры хранят описание внешнего вида окна и ссылку на обработчик сообщений, посылаемых окнам, которые будут созданы на базе данного класса.

Обработчик сообщений окна должен иметь следующий прототип:

LRESULT CALLBACK WindowProc(

HWND hWindow,

UINT message,

WPARAM wParam,

LPARAM lParam)

В параметре hWindow передается дескриптор окна, которому адресовано сообщение с кодом message. Интерпретация двух последних параметров зависит от типа пришедшего сообщения; в них передается дополнительная информация, необходимая для обработки.

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

LRESULT CALLBACK DefWindowProc(

HWND hWindow,

UINT message,

WPARAM wParam,

LPARAM lParam)

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

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

{

switch (msg)

{

// Выборка и обработка некоторых сообщений...

}

 

// Вызов обработчика по умолчанию

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

}

Описанный таким образом класс окна необходимо зарегистрировать вызовом функции RegisterClass или RegisterClassEx:

ATOM RegisterClass(WNDCLASS *windowClass);

ATOM RegisterClassEx(WNDCLASSEX *windowClass);

Наконец, на базе зарегистрированного класса можно создать окно. Для этого следует вызвать функцию CreateWindow или CreateWindowEx:

CreateWindow(

LPCSTR className,

LPCSTR windowName,

DWORD style,

int x,

int y,

int width,

int height,

HWND parent,

HMENU menu,

HINSTANCE hInstance,

LPVOID param);

 

CreateWindowEx(

DWORD exStyle,

LPCSTR className,

LPCSTR windowName,

DWORD style,

int x,

int y,

int width,

int height,

HWND parent,

HMENU menu,

HINSTANCE hInstance,

LPVOID param);

Функция CreateWindowEx отличается от CreateWindow возможностью задания дополнительных (расширенных) стилей exStyle для создаваемого окна. В остальном нет никаких отличий.

Чтобы создать окно, необходимо указать имя className зарегистрированного класса окна, его заголовок windowName, положение и размеры (x, y, width, height). Если окно является дочерним, в параметре parent следует указать дескриптор родительского окна. В параметре menu можно передать дескриптор меню.

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

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

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

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

{

static HWND hButton;

 

switch (msg)

{

case WM_CREATE:

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

hButton = CreateWindow("Button", "Button",

WS_CHILD|WS_VISIBLE, 10, 10, 100, 25,

hWnd, NULL, NULL, NULL);

break;

case WM_COMMAND:

// Если была нажата кнопка

if ((HWND)lParam == hButton)

{

MessageBox(hWnd, "Push button", "", 0);

}

break;

case WM_DESTROY:

// Завершение цикла выборки сообщений

PostQuitMessage(0);

break;

}

 

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

}

 

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int nCmdShow)

{

// Описание класса окна

WNDCLASS windowClass = { 0 };

windowClass.hInstance = hInstance;

windowClass.lpszClassName = "MainWindowClass";

windowClass.lpfnWndProc = (WNDPROC)WndProc;

windowClass.hbrBackground = (HBRUSH)COLOR_APPWORKSPACE;

windowClass.hCursor = LoadCursor(NULL, IDC_ARROW);

 

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

RegisterClass(&windowClass);

 

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

HWND hWnd = CreateWindow("MainWindowClass", "Main Window",

WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT,

CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL);

 

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

ShowWindow(hWnd, nCmdShow);

 

// Цикл выборки сообщений

MSG msg;

while (GetMessage(&msg, hWnd, 0, 0) > 0)

{

DispatchMessage(&msg);

}

 

return msg.wParam;

}

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

Сообщения изымаются из очереди вызовом функции GetMessage:

BOOL GetMessage(

LPMSG msg,

HWND hWindow,

UINT msgFilterMin,

UINT msgFilterMax);

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

В приведенном выше примере в обработчике сообщения создания окна WM_CREATE создается дочерний элемент управления – кнопка, – при этом использован предопределенный системой класс окна «Button». При нажатии на кнопку выводится сообщение «Push button». Разрушение окна WM_DESTROY завершает цикл выборки сообщений, в результате чего приложение заканчивает свою работу. Результат работы данного приложения показан на рисунке 14.

Рисунок 14 – Окно, определенное пользователем







©2015 arhivinfo.ru Все права принадлежат авторам размещенных материалов.