Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Проблема с циклом выборки сообщений


Страницы:   1 2

SPeller ©   (2009-12-21 05:10:00) 

Всем доброго времени суток!
Задача - при выполнении метода не возвращать управление в основной цикл выборки сообщений, а запустить свой цикл по фильтру пока не придет определенное сообщение. Наподобие того, как работает цикл модальной формы. Только мне нужно выхватывать из цикла не все сообщения, а только одно определенное. Код такой:


const
 AM_MARSHAL          = WM_USER + 51;

function ...
var
 msg: TMsg;
 doLoop, retReceived: Boolean;
 requestID: Cardinal;
begin
...
     doLoop := True;
     retReceived := False;
     while doLoop do
     begin
       while
         not retReceived and
         PeekMessage(msg, 0, AM_MARSHAL, AM_MARSHAL, PM_REMOVE or PM_NOYIELD) do
       begin
         // условие нормального возврата из цикла
         retReceived :=
           not proxyApt.ProcessMarshalMsg(msg.wParam, msg.дParam) and
           (PAptMarshalData(msg.wParam).ID = marshalData.ID);
       end;
       doLoop :=
         not retReceived and doLoop and
         not PeekMessage(msg, 0, WM_QUERYENDSESSION, WM_QUIT, PM_NOREMOVE or PM_NOYIELD);
       if doLoop then
         doLoop := WaitMessage;
     end;
...
end;


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


SPeller   (2009-12-22 02:44:00) [1]

Это я упрощенно написал пример с QS_POSTMESSAGE, чтобы знать как остановить поток. А с флагами и результатами да, на месте надо будет разбираться.


Игорь Шевченко   (2009-12-22 01:15:00) [2]

QS_ALLEVENTS

А это зачем ? Тебе же надо ждать только своих сообщений. И потом GetQueueStatus что-то возвращает, как ни странно.

Тебе скорее подойдет    MsgWaitForMultipleObjects(0, tmp, False, INFINITE, QS_POSTMESSAGE);


SPeller   (2009-12-22 00:42:00) [3]


> А зачем тут цикл-то ?
> Ты же  (см. цитату) ждешь всего одно интересующее тебя сообщение
> ?
Сейчас да, одно. Но оно может предназначаться не этому циклу, поэтому его понадобится пропустить и ждать следующее. В будущем может быть и не одно сообщение. И даже не по порядку. Сейчас сделал через GetMessage, всё отлично работает, но интересно разобраться что к чему чтобы в будущем на грабли не наступать.


> Для того, чтобы пометить неинтересные тебе невыбранные сообщения
> в очереди, как "старые", нужно вызвать GetQueueStatus с
> соответствующим флагом
Попробовал:

 while True do
 begin
   GetQueueStatus(QS_ALLEVENTS);
   WaitMessage;
 end;

Не помогло :) И вот так тоже

 tmp: Integer;
begin
 tmp := CreateEvent(nil, True, False, nil);
 while True do
 begin
   MsgWaitForMultipleObjects(1, tmp, False, INFINITE, QS_ALLEVENTS);
   WaitMessage;
 end;

Вобщем, фокусы с WaitMessage никак не проходят. А вот так получилось:

 tmp := 0;
 while True do
 begin
   GetQueueStatus(QS_ALLEVENTS);
   MsgWaitForMultipleObjects(0, tmp, False, INFINITE, QS_ALLEVENTS);
 end;

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


Игорь Шевченко   (2009-12-21 13:13:00) [4]

Leonid Troyanovsky ©   (21.12.09 12:56) [17]

Да, WaitMessage не помечает имеющиеся необработанные (и непомеченные) сообщения, как старые - она просто возвращает управление в этом случае.


> Это неточность, не знаю, стоит ли делать Add new content


А кто его знает, в обработке сообщений и так черт ногу сломит, они ж учитывают совместимость с Windows 3.x, я честно всегда стараюсь сообщения обрабатывать без особенных извратов :)


Leonid Troyanovsky   (2009-12-21 12:56:00) [5]


> Игорь Шевченко ©   (21.12.09 12:41) [15]

Цитата, видимо, из Remarks

This is because functions such as PeekMessage, GetMessage, GetQueueStatus, _WaitMessage_, MsgWaitForMultipleObjects, and MsgWaitForMultipleObjectsEx check the queue and then change the state information for the queue so that the input is no longer considered new.

Подчеркнуто мной.
Это неточность, не знаю, стоит ли делать Add new content
и насколько оно действенно.

--
Regards, LVT.


Leonid Troyanovsky   (2009-12-21 12:50:00) [6]


> SPeller ©   (21.12.09 08:48) [13]


> WaitMessage check the queue and then change the state

Ну, ты ж убедился, что в жизни это не так.

--
Regards, LVT.


Игорь Шевченко   (2009-12-21 12:41:00) [7]


> Хотя в мсдн написано что она должна возвращаться только
> тогда, когда приходят новые сообщения, вне зависимости от
> количества оных в очереди на момент ее вызова


Это ты чего-то не так прочитал.

The WaitMessage function yields control to other threads when a thread has no other messages in its message queue

Для того, чтобы пометить неинтересные тебе невыбранные сообщения в очереди, как "старые", нужно вызвать GetQueueStatus с соответствующим флагом, но при этом сообщения могут потеряться (Ну или Get/PeekMessage,MsgWaitForMultipleObjects).
То есть, WaitMessage не предназначена для того, чтобы отправлять поток в спячку, если в очереди нет сообщения определенного типа.

Рихтер по этому поводу довольно подробно пишет, его можно почитать.

Система помещает в очередь потока только сообщения ввода (WM_KEY, ...WM_MOUSE) и таймера, все остальные сообщения она посылает синхронно. Quit и Paint в очередь не посылаются, для них в очереди выставляются флажки.
Приложения, разумеется, могут ставить в очередь сообщения, но система ставит только перечисленные. Ну и соответственно, у очереди имеются флаги, какого типа НЕОБРАБОТАННЫЕ сообщения в ней находятся.

Вызвав GetQueueStatus (QS_POSTMESSAGE) ты узнаешь, что в очереди имеется сообщение, поставленное не системой, а, скажем, другим потоком (ну или этим же).


Сергей М.   (2009-12-21 12:39:00) [8]


> свой цикл по фильтру пока не придет определенное сообщение


А зачем тут цикл-то ?
Ты же  (см. цитату) ждешь всего одноинтересующее тебя сообщение ?

if GetMessage(.. твой фильтр ..) then //ждешь если в очереди нет сообщения, соответствующего фильтру, или немедленно получаешь его, если иначе
.. обрабатывай его ..
else
.. потоку послано WM_QUIT ..


SPeller   (2009-12-21 08:48:00) [9]


> А где видно, что они не пришли, новые-то сообщения?

Приложение запущено, висит в указанном выше цикле, запущен Task Manager и показывает в трее постоянную 100%-ю загрузку проца. В обычном режиме этого быть не должно однозначно.


> Ну, а где ж "выборка сообщений"?
> Это PeekMessage with PM_REMOVE.
> Или GetMessage, но без WaitMessage.

А как же functions such WaitMessage check the queue and then change the stateinformation for the queue so that the input is no longer considered new? Тут ведь явно написано что функция WaitMessage должна пометить очередь как не содержащую новых событий, в результате чего WaitMessage function suspends the thread and does not return until a newmessage is placed in the thread's message queue...


Leonid Troyanovsky   (2009-12-21 08:27:00) [10]


> SPeller ©   (21.12.09 08:03) [10]

> Может, я что-то неправильно понимаю?
..
> цикл работает постоянно...

Ну, а где ж "выборка сообщений"?
Это PeekMessage with PM_REMOVE.
Или GetMessage, но без WaitMessage.

--
Regards, LVT.


Вариант   (2009-12-21 08:05:00) [11]

SPeller ©   (21.12.09 06:56) [8]

> Вполне возможно, что они и пришли уже


> WaitMessage должен ждать прихода новых сообщений, вне зависимости,
>  сколько сообщений в очереди на момент вызова.


Не совсем так, это вольный перевод/интерпретация, но не затевая спора повторю вопрос иначе - А где видно, что они не пришли, новые-то сообщения? При работе с отладчиком я получаю как минимум несколько новых. Да и без него они есть, то перерисовка, то мышка двинулась то еще что-то.


> msdn говорит что GetMessage реагирует только на WM_QUIT,
>  а если нужно обработать WM_QUERYENDSESSION?

Это тоже вольный перевод(хотя надо признать и я не знаток английского). В MSDN говорится, что функция вернет 0 на WM_QUIT, и WM_QUIT будет принят независимо от фильтра, но я не прочитал, что она не примет сообщение WM_QUERYENDSESSION (если WM_QUERYENDSESSION  не исключена фильтром)


SPeller   (2009-12-21 08:03:00) [12]

Может, я что-то неправильно понимаю?

The WaitMessage function suspends the thread and does not return until a new message is placed in the thread's message queue

Note that WaitMessage does not return if there is unread input in the message queue after the thread has called a function to check the queue. This is because functions such as ... WaitMessage, ... check the queue and then change the state information for the queue so that the input is no longer considered new. A subsequent call to WaitMessage will not return until new input of the specified type arrives. The existing unread input (received prior to the last time the thread checked the queue) is ignored.


Но при этом даже вот в таком случае:

procedure TForm1.Button5Click(Sender: TObject);
begin
 while True do
     WaitMessage;
end;


цикл работает постоянно...

Может, дело в том, что WaitMessage вызывается из обработчика сообщения?


SPeller   (2009-12-21 07:09:00) [13]

С GetMessage всё хорошо, и код меньше. Но всё-равно интересует, почему с PeekMessage/WaitMessage не получается сделать красиво? Вдруг понадобится более сложная фильтрация сообщений? msdn говорит что GetMessage реагирует только на WM_QUIT, а если нужно обработать WM_QUERYENDSESSION?


SPeller   (2009-12-21 06:56:00) [14]


> Вполне возможно, что они и пришли уже

WaitMessage должен ждать прихода новых сообщений, вне зависимости, сколько сообщений в очереди на момент вызова.


> можно наверное посмотреть для твоей цели функцию GetMessage?

Ага, согласен


Вариант   (2009-12-21 06:50:00) [15]


> SPeller ©   (21.12.09 05:10)


> Проблема в том, что WaitMessage не ждет новых сообщений
> и возвращается сразу же

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


SPeller   (2009-12-21 05:42:00) [16]

Проблема не в загрузке проца, а в том, что WaitMessage не выполняет своих функций, хотя вроде всё по msdn. Почему - надо разобраться.


brother   (2009-12-21 05:37:00) [17]

> а решить ее :)

имхо, проблема нагрузки проца - решена)


SPeller   (2009-12-21 05:36:00) [18]

Цель не замаскировать проблему, а решить ее :)


brother   (2009-12-21 05:30:00) [19]

> не грузит проц, но цикл так же работает постоянно. Думаю
> что это как-то неправильно

ты хотел разгрузить проц? разгрузил? ;)
зы можно еще подумать)


SPeller   (2009-12-21 05:27:00) [20]

Со Sleep(1) не грузит проц, но цикл так же работает постоянно. Думаю что это как-то неправильно


Страницы:   1 2

Наверх

Титульная страница Поиск, карта сайта Написать письмо