Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Создание эффективных приложений для Windows Джеффри Рихтер 2004 (Книга).pdf
Скачиваний:
377
Добавлен:
15.06.2014
Размер:
8.44 Mб
Скачать

быстрая. Если бы это сообщение посылалось всякий раз, когда окно становится недействительным, быстродействие системы снизилось бы весьма ощутимо. Но по мещая WM_PAINT после ввода с клавиатуры, система работает гораздо быстрее. На пример, из меню можно вызвать какую-нибудь команду, открывающую диалоговое окно, выбрать в нем что-то, нажать клавишу Enter — и проделать все это даже до того, как окно появится на экране. Достаточно быстро нажимая клавиши, Вы наверняка за метите, что сообщения об их нажатии извлекаются прежде, чем дело доходит до со общений WM_PAINT. А когда Вы нажимаете клавишу Enter, подтверждая тем самым значения параметров, указанных в диалоговом окне, система разрушает окно и сбра сывает флаг QS_PAINT

Приоритет WM_TIMER еще ниже, чем WM_PAINT. Почему? Допустим, какая-то программа обновляет свое окно всякий раз, когда получает сообщение WM_TIMER. Если бы оно поступало слишком часто, программа просто не смогла бы обновлять свое окно Но поскольку сообщения WM_PAINT обрабатываются до WM_TIMER, такая проблема не возникает.

NOTE

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

Пробуждение потока с использованием объектов ядра или флагов состояния очереди

Функции GetMessage и PeekMessage приостанавливают поток до тех пор, пока ему не понадобится выполнить какую-нибудь задачу, связанную с пользовательским интер фейсом. Иногда то же самое было бы удобно и при обработке других задач. Для этого поток должен как-то узнавать о завершении операции, не относящейся к пользова тельскому интерфейсу.

Чтобы поток ждал собственных сообщений, вызовите функцию MsgWaitForMultiple Objects или MsgWaitForMultipleObjectsEx:

DWORD MsgWaitForMultipleOb]ects( DWORD nCount, PHANDLE phOb]ects, BOOL fWaitAll, DWORD dwMilUseconds, DWORD dwWakeMask);

DWORD MsgWaitForMultipleObjectsEx( DWORD nCount, PHANDLE phObjects, DWORD dwMilUseconds,DWORD dwWakeMask, DWORD dwFlags);

Эти функции аналогичны WaitForMultipleObjects (см главу 9). Разница в том, что при их использовании поток становится планируемым, когда освобождается какой нибудь из указанных объектов ядра или когда оконное сообщение нужно переслать окну, созданному этим потоком.

Внутренне система просто добавляет объект ядра "событие" в массив описателей ядра Параметр dwWakeMask сообщает системе, в какой момент объект-событие дол жно переходить R свободное состояние. Его допустимые значения идентичны тем, которые можно передавать в функцию GetQueueStatus.

WaitForMultipleObjects обычно возвращает индекс освобожденного объекта (в диа пазоне от WAIT_OBJECT_0 до WAIT_OBJECT_0 + nCount - 1). Задание параметра dwWa keMask

равносильно добавлению еще одного описателя При выполнении условия, определенного

маской пробуждения,MsgWaitForMullipleObjects(Ex) возвращает значе ние

WAIT_OBJECT_0 + nCount.

Вот пример вызова MsgWaitForMultipleObjects

MsgWaitForMultipleObjects(0, NULL, TRUE, INFINITE, QS_INPUT);

Описатели синхронизирующих объектов в этом операторе не передаются — па раметры nCount и phObjects равны соответственно 0 и NULL. Мы указываем функции ждать освобождения всех объектов Но в действительности задан лишь один объект, и с тем же успехом параметру fWaitAll можно было бы присвоить знячение FALSE. Мы также сообщаем, что будем ждать — сколько бы времени это ни потребовало — появ ления в очереди ввода потока сообщения от клавиатуры или мыши.

Начав пользоваться функцией MsgWaitForMultipleObjects в своих программах, Вы быстро поймете, что она лишена многих важных качеств. Вот почему Microsoft при шлось создать более совершенную функцию MsgWaitForMultipleObjectsEx, которая по зволяет задать в параметре dwFlags любую комбинацию следующих флагов.

Флаг

Описание

 

 

MWMO_WAITALL

Функция ждет освобождения всех объектов ядра и появления в

 

очереди потока указанных сообщений (без этого флага функ

 

ция ждет освобождения одного из объектов ядра или появле

 

ния в очереди одного из указанных сообщений)

 

 

MWMO_ALERTABLE

Функция ждет в «тревожном» состоянии

MWMO_INPUTAVAILABLE Функция ждет появления в очереди потока одного из указан ных сообщений

Если Вам не нужны эти дополнительные возможности, передайте в dwFlags нуле вое значение.

При использовании MsgWaitForMultipIeObjects(Ex) учитывайте, что.

эти функции лишь включают описатель внутреннего объекта ядра «событие» в массив описателей объектов ядра, и значение параметра nCount не должно превышать 63 (MAXIMUM_WAIT_OBJECTS - 1);

если в параметре fWaitAll передастся FALSE, функции возвращают управление при освобождении объекта ядра или при появлении в очереди потока сооб щения заданного типа,

если в параметре fWaitAll передается TRUE, функции возвращают управление при освобождении всех объектов ядра и появлении в очереди потока сообщения заданного типа. Такое поведение этих функций преподносит сюрприз многим разработчикам Ведь очень часто поток надо пробуждать при освобож дении всех объектов ядра или при появлении сообщения указанного типа. Но функции, действующей именно так, нет; при вызове любая из этих функций на самом деле проверяет в очереди пото ка

только новые сообщения заданного типа.

Заметьте, что и последняя особенность этих функций — не очень приятный сюр приз для многих разработчиков. Возьмем простой пример Допустим, в очереди по токи находятся два сообщения о нажатии клавиш. Если теперь вызвать MsgWaitForMul tipleObjects(Ex) и

задать в dwWakeMask значение QS_INPUT, поток пробудится, извле чет из очереди первое сообщение и обработает его Но на повторный вызов MsgWait ForMultipleObjects(Ex) поток никак не отреагирует — ведь новых сообщений в очере ди нет.

Этот механизм создал столько проблем разработчикам, что Microsoft пришлось добавить в

MsgWaitForMultipleObjectsEx поддержку флага MWMO_INPUTAVATLABLE

Вот как надо писать цикл выборки сообщений при использовании MsgWaitForMul tipleObjectsEx

BOOL fQuit = FALSE; // надо ли завершить цикл?

while (!fQuit)

{

//поток пробуждается при освобождении обьекта ядра

ИЛИ

//для обработки сообщения от пользовательского интерфейса

DWORD dwResult = MsgWaitForMultipleObjectsEx(1, &hEvent, INFINITE, QS_ALLEVENTS, MWMO_INPUTAVAILABLE);

switch (dwResult}

{

case WAIT_OBJECT_0:

// освободилось событие break;

case WAIT_OBJECT_0 + 1:

//в очереди появилось сообщение

//разослать все сообщения MSG msg;

while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))

{

if (msg.message == WM_QUIT)

{

// сообщение

WM_QUIT - выходим из цикла

fQuit = TRUE;

}

else

{

// транслируем и пересылаем сообщение

TranslateMessage(

&msg);