![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Будет ли форма получать и обрабатывать сообщения при ожидании? [D7, WinXP]
Aleksandr. © (2004-09-21 16:08:00)В методе окна запускается поток, и окно ждет его завершения через WaitForSingleObject в цикле. Но этот поток может через PostMessage отправлять сообщения этому окну. Вот я и запутался совсем - будет ли оно в этом состоянии получать и обрабатывать эти сообшения? И как вообще правильнее это организовать, если такой подход неприемлем?
KSergey (2004-09-22 11:42:00) [21]Скорее всего вместо вот этого
> MsgWaitForMultipleObjects(2,F,false,1000,QS_PostMessage)
Надо написать
MsgWaitForMultipleObjects(2,F[0],false,1000,QS_PostMessage)
А вообще сам сейчас страдаю... Хотя бы для тек. процесса... И нифига.. Первый раз проходит сразу (ну ладно, возможно сообщения есть), а на второй - "неверный дескриптор"...
Делаю так:
var
rrr: DWORD;
pH: THandle;
begin
pH := GetCurrentThread;
........
while .... do
begin
rrr := MsgWaitForMultipleObjects(1, pH, FALSE, INFINITE, QS_ALLINPUT);
if rrr = WAIT_FAILED then RaiseLastWin32Error;
...
end;
И нифига... (в смысле вышеуказанная бяка).
Если вместо GetCurrentThread поставить GetCurrentProcess - никогда в MsgWaitForMultipleObjects не задерживается...
Aleksandr. (2004-09-21 17:33:00) [22]Нифига не пойму. Сделал для теста:
type
TTestThread = class (TThread)
Event : HWND;
FormH : Hwnd;
constructor Create(aEv,aH : HWND);
procedure Execute; override;
end;
procedure TForm1.Button8Click(Sender: TObject);
var
T : TTestThread;
A : HWND;
D : cardinal;
begin
A:=CreateEvent(nil,true,false,nil);
T:=TestThread.Create(A,Handle);
T.Resume;
repeat
D:=MsgWaitForMultipleObjects(1,A,false,1000,QS_AllINPUT)
until D=Wait_Object_0+1;
T.Terminate;
T.Free;
CloseHandle(A)
end;
constructor TestThread.Create;
begin
Inherited Create(true);
FormH:=aH;
Event:=aEv
end;
procedure TestThread.Execute;
var
i : integer;
begin
for i:=0 to 4 do begin
Sleep(500);
PostMessage(FormH,um_1,0,0)
end;
SetEvent(Event)
end;
procedure TForm1.DoMsg(var Message: TMessage); {message UM_1}
begin
LB.Items.Add('!')
end;
и сразу же срабатывает D=Wait_Object_0+1. А если ставлю маску QS_PostMessage - разница только в том, что уже после выхода из цикла форма вставляет в листбокс все полученные "!".
А если пытаюсь так:
var
..
F : array [0..1] of hwnd;
begin
A:=CreateEvent(nil,true,false,nil);
T:=TestThread.Create(A,Handle);
F[0]:=A;
F[1]:=UM_1;
T.Resume;
repeat
D:=MsgWaitForMultipleObjects(2,F,false,1000,QS_PostMessage)
until D=Wait_Object_0+1;
то вообще все умирает :(
Digitman (2004-09-21 17:03:00) [23]
> или он будет просыпаться от любых сообщений?
именно !
Aleksandr. (2004-09-21 17:00:00) [24]Опять не понял. Так в массив хэндлов ему нужно указывать, какие сообщения должны его пробуждать или он будет просыпаться от любых сообщений? И что должно быть в параметре fWaitAll? Мне же не нужно, чтобы он посчитал результат =Wait_Object_0, если не было установлено событие.
Digitman (2004-09-21 16:49:00) [25]да, MsgWaitFor-вызов вернет управление ЛИБО при срабатывании указанного объекта синхр-ции ЛИБО при непустой очереди сообщений
Aleksandr. (2004-09-21 16:39:00) [26]Digitman © :
Ой, а можно подробнее? Я по Вашей подсказке нашел MsgWaitForMultipleObjects, только не совсем понял, как он работает. Насколько я понял, ему в хэндлы загоняется созданный эвент и сообщения, которые будут посылаться из ожидаемого потока, а в маску QS_POSTMESSAGE, и тогда, помимо выхода из ожидания по SetEvent, он будет также выходить и как только придет какое-то из упомянутых сообщений?
Digitman (2004-09-21 16:21:00) [27]
> Надо же, чтобы приложение не выглядило повисшим
а это означает, что осн.трэд, желающий того, должен в таких "узких местах" пользовать MsgWaitFor.. вместо WaitFor..
Aleksandr. (2004-09-21 16:21:00) [28]clickmaker © :
Кстати, по поводу ProcessMessages. Есть жестокая вещь с ним у меня - вызов его в окне, получающем сообщения от потока, приводит к моментальному выпадению программы. А из Делфи - к дебагу ЦПУ. Проще говоря, сначала я пытался сделать так
...
FUpdator.Resume;
repeat
Application.ProcessMessages
until FUpdator.Terminated;
Вот тогда это и выплыло. Поменял на
A:=CreateEvent(nil,true,false,PChar('Updator'));
try
FUpdator.StopEvent:=A;
FUpdator.Resume;
Repeat
D:=WaitForSingleObject(A,5000)
until (D=Wait_Object_0) OR (D=WAIT_ABANDONED)
finally
CloseHandle(A)
end;
а затем задался сим вопросом.
Aleksandr. (2004-09-21 16:16:00) [29]KSergey © :
Увы, моду диктуют цели. Надо же, чтобы приложение не выглядило повисшим, пока что-то им делается.
clickmaker (2004-09-21 16:16:00) [30]Есть альтернатива потоку - Application.ProcessMessages()
Но если фоновая операция достаточно трудоемкая и, тем более, непрерывная, то лучше поток
Aleksandr. (2004-09-21 16:14:00) [31]Млин. А как же быть с визуализацией - прогрессбаром в этом окне, например, показывающем процент выполнения потоком задач, который обновляется тоже сообщениями, посылаемыми из потока?
KSergey (2004-09-21 16:14:00) [32]модельное = модальное
KSergey (2004-09-21 16:13:00) [33]Да просто сделать модельное окно - вот и все. Как поток заканчивается - шлем окну WM_CLOSE
Вот только мне упорно не понятна эта мода на потоки... Прога все равно стоит на месте - на кой тогда этот поток-то нужен??? Мода?
clickmaker (2004-09-21 16:11:00) [34]Не будет
Если нужно узнать о завершении потока, можно просто послать окну соответствующее сообщение