logo
Методичка по курс_Windows

5.3 Посылка асинхронных сообщений в очередь потока

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

BOOL PostMessage( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

При вызове этой функции система определяет, каким потоком создано окно, идентифицируемое параметром hwnd, Далее система выделяет блок памяти, сохраняет в нем параметры сообщения и записывает этот блок в очередь асинхронных сообщений данного потока. Кроме того, функция устанавливает флаг пробуждения QS_POST MESSAGE (о нем — чуть позже). Возврат из PostMessage происходит сразу после того, как сообщение поставлено в очередь, поэтому вызывающий поток остается в неведении, обработано ли оно процедурой соответствующего окна. На самом деле вполне вероятно, что окно даже не получит это сообщение Такое возможно, если поток, создавший это окно, завершится до того, как обработает все сообщения из своей очереди.

Сообщение можно поставить в очередь асинхронных сообщений потока и вызовом PostThreadMessage:

BOOL PostThreadMessage (DWORD dwThreadId, UINT uMsg, WPARAM wParam, LPARAM lParam);

Какой поток создал окно, можно определить с помощью GetWindowThreadPro cessId:

DWORD GetWindowThreadProcessId (HWND hwnd PDWORD pdwProccssId);

Она возвращает уникальный общесистемный идентификатор потока, который создал окно, определяемое параметром hwnd. Передав адрес переменной типа DWORD в параметре pdwProcessId, можно получить и уникальный общесистемный идентификатор процесса, которому принадлежит этот поток. Но обычно такой идентификатор не нужен, и мы просто передаем NULL.

Нужный поток идентифицируется первым параметром, dwThreadId.Когда сообщение помещено в очередь, элемент hwnd структуры MSG устанавливается как NULL. Применяется эта функция, когда приложение выполняет какую то особую обработку в основном цикле выборки сообщений потока, — в этом случае он пишется так, что бы после выборки сообщения функцией GetMessage (или PeekMessage) код в цикле сравнивал hwnd с NULL и, выполняя эту самую особую обработку, мог проверить значение элемента msg структуры MSG. Если поток определил, что сообщение не адресовано какому-либо окну, DispatchMessage не вызывается, и цикл переходит к выборке следующего сообщения.

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

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

VOID PostOuitMessage(int nExilCode);

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

PostThreadMessage(GetCurrentThreadId(), WM_OUIT, nExitCode, 0);

Но в действительности PostQuitMessage не помещает сообщение ни в одну из очередей структуры THREADINFO. Эта функция просто устанавливает флаг пробуждения QS_QUIT (о нем я тоже расскажу чуть позже) и элемент nExitCode структуры THREAD INFO. Так как эти операции не могут вызвать ошибку, функция PostQuitMessage не возвращает никаких значений (VOID).