пользователей: 30398
предметов: 12406
вопросов: 234839
Конспект-online
РЕГИСТРАЦИЯ ЭКСКУРСИЯ

Оконные сообщения. Синхронная посылка сообщений. Особенности

Оконное сообщение можно отправить непосредственно оконной процедуре вызовом SendMessage:

LRESULT SendMessage( HWNO hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

Оконная процедура обработает сообщение, и только по окончании обработки функция SendMessage вернет управление. Благодаря этому ее используют гораздо чаще, чем PostMessage или PostThreadMessage.
При переходе к выполнению следующей строки кода поток, вызвавший SendMessage, может быть уверен, что сообщение уже обработано.
Свойства:
Поведение функции SendMessage сильно зависит от того, какому потоку принадлежит окно hwnd.
Если это тот же поток, что и поток-отправитель сообщения, то SendMessage просто вызывает оконную процедуру как подпрограмму. Закончив обработку, оконная процедура передает функции SendMessage некое значение, а та возвращает его вызвавшему потоку.
lВсе усложняется, если это другой поток (безразлично в этом или другом процессе). В этом случае ОС выполняет следующие действия:
1. переданное сообщение присоединяется к очереди синхронных сообщений потока-приемника. Поток-приемник извещается об этом при помощи флага состояния очереди сообщений QS_SENDMESSAGE,
2. если в данный момент поток-приемник не ждет никаких сообщений, он не прерывается и продолжает выполняться,
l3. после того как поток-приемник готов принять сообщение он проверяет (при условии, что статус очереди QS_SENDMESSAGE) очередь синхронных сообщений. Найдя отправленное сообщение поток обрабатывает его и сбрасывает флаг QS_SENDMESSAGE,
l4. обработав сообщение и получив его результат, поток-приемник отправляет (асинхронным образом) этот результат в очередь ответных сообщений потока-отправителя.
lВсе это время поток-отправитель простаивает, ожидая ответа в очереди ответных сообщений. После получения ответа он возобновляет работу.
lПоскольку ОС обрабатывает синхронные сообщения подобным образом, то Ваш поток может "зависнуть", ожидая ответа от потока, который, например, вошел в бесконечный цикл.
lЭто верно даже в том случае, если оба потока принадлежит одному процессу.
lИзбегать подобных ситуаций позволяют четыре функции, и первая из них — SendMessageTimeout:

LRESULT SendMessageTimeout( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT fuFlags, UINT uTimeout, PDWORD_PTR pdwResult);

lОна позволяет задавать отрезок времени, в течение которого Вы готовы ждать ответа от другого потока на Ваше сообщение. Ее первые четыре параметра идентичны параметрам функции SendMessage.
lВ параметре fuFlags можно передавать флаги:

Значение

Описание

SMTO_NORMAL

или 0. Означает отсутствие каких-либо

дополнительных условий ожидания

SMTO_ABORTIFHUNG

проверка потока-приемника на "зависание". Поток

считается зависшим, если он прекращает обработку

событий более чем на 5 с. Если поток "завис"

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

SMTO_BLOCK

предотвращает любую обработку синхронных

сообщений до возврата из SendMessageTimeout

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

BOOL SendMessageCallback( HWND hwnd, UINT uHsg, WPARAM wParam, LPARAM Param, SENDASYNCPROC pfnResultCallBack, ULONG_PTR dwData);

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

VOID CALLBACK ResultCallBack( HWND hwnd. UINT uMsg, ULONG_PIR dwData, LRESULT lResult);

lСуществует и другое применение функции SendMessageCallback.
lВ Windows предусмотрен метод, позволяющий разослать сообщение всем перекрывающимся окнам (overlapped windows) в системе; он состоит в том, что Вы вызываете SendMessage и в параметре hwnd передаете ей HWND_BROADCAST (определенный как -1).
lЭтот метод годится только для широковещательной рассылки сообщений, возвращаемые значения которых Вас не интересуют, поскольку функция способна вернуть лишь одно значение, LRESULT.
lНо, используя SendMessageCallback, можно получить результаты обработки "широковещательного" сообщения от каждого перекрытого окна.
lЕсли SendMessageCallback вызывается для отправки сообщения окну, созданному вызывающим потоком, система немедленно вызывает оконную процедуру, а после обработки сообщения — функцию ResultCallBack. После возврата из ResultCallback выполнение начинается со строки, следующей за вызовом SendMessageCallback.
lТретья функция, предназначенная для передачи межпоточных сообщений:

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

lПоместив сообщение в очередь синхронных сообщений потока-приемника, она немедленно возвращает управление вызывающему потоку, т.е. ведет себя и PostMessage. Но два отличия SendNotifyMessage от PostMessage все же есть:
lВо-первых, если SendNotifyMessage посылает сообщение окну, созданному другим потоком, приоритет данного синхронного сообщения выше приоритета асинхронных сообщений, находящихся в очереди потока-приемника. Иными словами, сообщения, помещаемые в очередь с помощью SendNolifyMessage, всегда извлекаются до выборки сообщений, отправленных через PostMessage.
lВо-вторых, если сообщение посылается окну, созданному вызывающим потоком, SendNotifyMessage работает точно так же, как и SendMessage, т. e не возвращает управление до окончания обработки сообщения.
lБольшинство синхронных сообщений посылается окну для уведомления – чтобы сообщить ему об изменении состояния и чтобы оно как-то отреагировало на это, прежде чем Вы продолжите свою работу.
lНапример, WM_ACTIVATE, WM_DESTROY, WM_ENABLE, WM_SIZE, WM_SETFOCUS, WM_MOVE и многие другие сообщения – это просто уведомления, посылаемые системой окну в синхронном, а не асинхронном режиме.
lПоэтому система не прерывает свою работу только ради того, чтобы оконная процедура могла их обработать.
lПрямо противоположный эффект дает отправка сообщения WM_CREATE — тогда система ждет, когда окно закончит его обработку. Если возвращено значение -1, значит, окно не создано. 
lНаконец, четвертая функция, связанная с обработкой межпоточных сообщений:

BOOL ReplyMessage(LRESULT lResult);

lОна отличается от трех описанных выше. В то время как Send-функции используются посылающим сообщения потоком для защиты себя от зависания, ReplyMessage вызывается потоком, принимающим оконное сообщение.
lВызвав ее, поток как бы говорит системе, что он уже получил результат обработки сообщения и что этот результат нужно упаковать и асинхронно отправить в очередь ответных сообщений потока-отправителя. Последний сможет пробудиться, получить результат и возобновить работу.
lЕсли Вас интересует, является обрабатываемое сообщение внутрипоточным или межпоточным, вызовите функцию InSendMessage:

BOOL InSendMessage();

lОна возвращает TRUE, если поток обрабатывает межпоточное синхронное сообщение, и FALSE — при обработке им внутрипоточного сообщения (синхронного или асинхронного).
lЕсть еще одна функция, позволяющая определить тип сообщения, которое обрабатывается Вашей оконной процедурой:

DWORD InSendMessageEx(PVOID pvReserved);

lВызывая ее, Вы должны передать NULL в параметре pvReserved. Возвращаемое значение указывает на тип обрабатываемого сообщения.
lЗначение ISMEX_NOSEND (0) говорит о том, что поток обрабатывает внутрипоточное синхронное или асинхронное сообщение. Остальные возвращаемые значения представляют собой комбинацию битовых флагов:

Флаг

Описание

ISMEX_ SEND

Поток обрабатывает межпоточное синхронное сообщение, посланное через SendMessage или SendMessageTimeout; если флаг ISMEX REPLIED не установлен, поток-отправитель блокируется в ожидании ответа

ISMEX_NOTIFY

Поток обрабатывает межпоточное синхронное сообщение, посланное через SendNotify Message, поток- отправитель не ждет ответа и не блокируется

ISMEX_CALLBACK

Поток обрабатывает межпоточное синхронное сообщение, посланное через SendMessageCallback; поток- отправитель не ждет ответа и не блокируется

ISMEX_REPLIED

Поток обрабатывает межпоточпое синхронное сообщение и уже вызвал ReplyMessage; поток-отправитель не блокируется

 


26.12.2015; 23:37
хиты: 0
рейтинг:0
для добавления комментариев необходимо авторизироваться.
  Copyright © 2013-2024. All Rights Reserved. помощь