![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Объясните [D7, XP]
Sam Stone © (2007-03-07 07:53:00)Доброго времени суток. Как работать с GetMessage и PostThreadMessage? Хочется покидаться сообщениями в поток (в общеобразовательных целях). Делаю так (по примерам с мсдн и гугля):
function f1(p:pointer):dword;
var m:TMsg;
begin
PeekMessage(m,0,wm_user,wm_user,pm_noremove);//из дельфёвого хелпа
while GetMessage(m,0,0,0) do begin //или integer(GetMessage())>0
if m.message=SomeWalue then BlaBlaBla;
TranslateMessage(m);
DispatchMessage(m);
end;
end;
...
//запускаем поток
CloseHandle(BeginThread(nil,0,@f1,nil,0,ThreadIDVar));
...
//сообщение, например, по нажатию на кнопку
PostThreadMEssage(ThreadIDVar,wm_user+1,0,0);
При вызове GetMessage поток тихо помирает, т.е. в дебаге дальше не идет, по Ф8 программа запускается. С PeekMessage то же самое, разве что если использовать PM_NOREMOVE флаг и сперва в потоке запостить любое сообщение, то все будет крутиться, но другие мессаги я поймать не смог.
Понять в чем в данном случае проблема за неимением опыта не получается, поэтому прошу направить на путь истинный :)
Сергей М. (2007-03-07 12:50:00) [1]
> Sam Stone © (07.03.07 12:43) [14]
Разберись еще в назначении ф-ций TranslateMessage/DispatchMessage и действительной необходимости их вызова в твоемслучае (а в твоем случае из вызов избыточен) - вот тогда будет полное понимание.
Sam Stone (2007-03-07 12:43:00) [2]Теперь мне всё понятно ) спасибо :)
Сергей М. (2007-03-07 12:31:00) [3]
> это он так засыпает оригинально?
Он не засыпает, он ждетсообщения.
То сообщение wm_user+1, что ты послал однократно(т.е. без while-цикла), ушло "в пустоту", потому что в момент отправки очередь еще не существовала (она начнет существование только при первом вызове GetMessage в потоке-адресате).
Иными словами, цикл while not PostThreadMessage() гарантирует ожидание создания целевой очереди и достоверное помещение в эту очередь сообщения. Без этого цикла такой гарантии нет.
Sam Stone (2007-03-07 12:14:00) [4]
> Сергей М. © (07.03.07 12:08) [10]
кажется дошло ) т.е. это он так засыпает оригинально?
Sam Stone (2007-03-07 12:11:00) [5]
> Ты бы описал конкретно поставленную задачу ...
собсна вот она
> создать доп.поток, который должен реагировать на такие-то
> адресованные ему извне сообщения таким-то конкретным образом
НО! Если в коде
> CloseHandle(BeginThread(nil,0,@f1,nil,0,ThreadIDVar));
> while not PostThreadMEssage(ThreadIDVar,wm_user+1,0,0) do;
убрать while то произойдет непонятная ошибка в потоке при вызове GetMessage, после которой он (поток) прекратит свое выполнение. Меня интересует, почему такое происходит? Т.е. почему без while not PostThreadMEssage(ThreadIDVar,wm_user+1,0,0) do; код не работает(баг/косяк/кривые руки)?
[1] меня полностью удовлетворяет, я рад и кидаюсь сообщениями :) Но мне хочется понять суть вышеописанной ошибки.
Вроде бы все понятно описал.
Сергей М. (2007-03-07 12:08:00) [6]
> первый раз цикл отрабатывался, получая сообщение wm_user,
> а на следующей итерации поток умирал
Он не "умирал", он был блокирован на очередном выполнении GetMessage за отсутствием каких-либо сообщений в очереди. Единственное посланное wm_user-сообщение было выбрано при первой итерации, а больше в очереди ничего нет
Leonid Troyanovsky (2007-03-07 12:03:00) [7]
> Leonid Troyanovsky © (07.03.07 12:00) [8]
> У тебя пропущен stdcall, поэтому все и умирает.
Sorry, не заметил, что beginthread.
Но, в любом случае, причины смерти не в отсутствии очереди.
--
Regards, LVT.
Leonid Troyanovsky (2007-03-07 12:00:00) [8]
> Sam Stone © (07.03.07 11:36) [6]
> В качестве полноценного примера:
> function f2(p:pointer):dword;
> var m:TMsg;
> lb:longbool;
> begin
> lb:=GetMessage(n,0,0,0);
> sleep(0);//если поставить брякпоинт - никогда не сработает
> из-за вылета на GetMessage
> end;
> ...
> BeginThread(nil,0,@f2,nil,ThreadID);
У тебя пропущен stdcall, поэтому все и умирает.
Потоку создается очередь при вызове им _любой_ user32
функциии: хоть GetMessage, хоть PostMessage.
--
Regards, LVT.
Сергей М. (2007-03-07 11:51:00) [9]
> Sam Stone © (07.03.07 11:36) [6]
Мне не совсем понятна цель твоих экспериментов.
Ты бы описал конкретно поставленную задачу ...
Ну, например, создать доп.поток, который должен реагировать на такие-то адресованные ему извне сообщения таким-то конкретным образом....
В моем примере созданный поток явно реагирует на сообщение WM_USER+1 запуском процедуры BlaBlaBla, все прочие сообщения (кроме WM_QUIT) диспетчеризует по-умолчанию, при получении WM_QUIT немедленно завершает работу.
?
Sam Stone (2007-03-07 11:36:00) [10]Нет, я не про то... Если убрать while not PostThreadMessage при выполнении GetMessage поток тихо умрет. try except не помогает, посмотреть результат через variable:=GetMessage() тоже не получается. Цикл даже не отрабатывается ни разу.
Когда делал так
function f1(p:pointer):dword;
...
begin
PostThreadMessage(GetCurrentThreadID,wm_user,0,0);
while GetMessage(m,0,0,0) do begin
end;
то первый раз цикл отрабатывался, получая сообщение wm_user, а на следующей итерации поток умирал. При этом не удалось установить, что возвращает GetMessage. Даже watch подвис :). Такое ощущение, что при пустой очереди происходит эксепшн.
В качестве полноценного примера:
function f2(p:pointer):dword;
var m:TMsg;
lb:longbool;
begin
lb:=GetMessage(n,0,0,0);
sleep(0);//если поставить брякпоинт - никогда не сработает из-за вылета на GetMessage
end;
...
BeginThread(nil,0,@f2,nil,ThreadID);
Сергей М. (2007-03-07 11:06:00) [11]"Смерть" потока связана с посылкой ему сообщения WM_QUIT.
GetMessage() создает очередь (если она еще не создана) и выбирает из ее головы сообщения (если очередь пуста, ф-ция блокирует выполнение потока до момента появления в очереди хотя бы одного сообщения).
WM_QUIT является специальнымпредопределенным сообщением, при выборке которого ф-ция возвращает False (для любых иных выбранных сообщений ф-ция возвращает True). Как только ф-ция вернет False, WHILE-цикл, в котором она вызывается, прерывает свою работу.
Sam Stone (2007-03-07 09:41:00) [12]а с чем тогда связана смерть потока на GetMessage, если убрать while not PostThreadMessage? Не могу понять... Пост уходит в никуда, т.к. нет очереди, а очередь создается через гет/пик...
Сергей М. (2007-03-07 09:20:00) [13]
> Sam Stone © (07.03.07 08:46) [2]
> долбить пока не будет создана очередь?
Да.
Если очередь не создана, то сообщение будет послано "в пустоту", о чем и скажат False-результат вызова PostThreadMEssage().
А очередь будет создана при первом вызове WaitMessage/GetMessage/PeekMessage
Sam Stone (2007-03-07 08:46:00) [14]Спасибо. А с чем связано
> while not PostThreadMEssage(ThreadIDVar,wm_user+1,0,0) do;
?
долбить пока не будет создана очередь?
Сергей М. (2007-03-07 08:17:00) [15]function MyThreadFunc(p:pointer):dword;
var
m:TMsg;
begin
while GetMessage(m,0,0,0) do
case m.Message of
WM_USER+1: BlaBlaBla;
else
TranslateMessage(m);
DispatchMessage(m);
end;
end;
...
CloseHandle(BeginThread(nil,0,@f1,nil,0,ThreadIDVar));
while not PostThreadMEssage(ThreadIDVar,wm_user+1,0,0) do;
..
//по получению этого сообщения потчная функция завершит свою работу
PostThreadMEssage(ThreadIDVar, WM_QUIT,0,0);