Здравствуйте, DDDDD, Вы писали:
DDD>Подскажите как обработать PostMessage в потоке. DDD>Пробовал PostThreadMessage(GetWindowThreadProcessId(MyConnectionThread.Handle),WM_MY,1,1) — эффекта ноль..
У потока должна быть организована очередь сообщений.
Для этого можно завести окно (AllocateHWND) и в его оконной функции ловить сообщения, или вовсе без окна — в начале работы потока вызвать PeekMessage (тогда организуется очередь), а потом в поточной функции проверять GetMessage (т.е. цикл выборки сообщений)
Re: Как обработать PostMessage в потоке TThread
От:
Аноним
Дата:
30.03.10 09:52
Оценка:
Здравствуйте, DDDDD, Вы писали:
DDD>Подскажите как обработать PostMessage в потоке. DDD>У меня есть поток: DDD> MyConnectionThread : TConnectionThread;
DDD>type DDD> TConnectionThread = class(TThread) DDD> procedure MyCoolHandler(var MyMessage: TMessage); message WM_MY; DDD> private DDD> { Private declarations } DDD> protected DDD> procedure Execute; override; DDD> end;
DDD>Если я в Execute отправляю PostMessage форме ( PostMessage(Form1.Handle,WM_MY,2,1) то форма его получает.
DDD>Но не получается обратно! то есть вопрос как из основного потока передать сообщение и обработать его внутри потока?
DDD>Пробовал PostThreadMessage(GetWindowThreadProcessId(MyConnectionThread.Handle),WM_MY,1,1) — эффекта ноль..
Элементарно.
1. Заведи MessageLoop в своём потоке. Создай в своём потоке WindowHandle и PeekMessage,GetMessage переодически
2. Второй вариант гораздо хуже. Т.к. очереди не будет. Она будут из одного элемента
PostThreadMessage(thread.Handle,WM_MY,a,b); -- проигнорирует если предыдущее сообщение ещё не обработано.
...
в потоке должно быть вызвано
PeekMessage(msg,0, WM_USER, WM_USER, PM_NOREMOVE); -- Это заведёт очередь для этого потока. Заодно заведи Event для проверки готовности приёма команд.
и потом переодически вызываешь GetMessage или PeekMessage что бы проверить а не пришла какая-нибуть хрень
3. Заведи ThreadSafeQueue и не пользуйся виндовыми подвисающими очередями событий :P
Re[2]: Как обработать PostMessage в потоке TThread
Здравствуйте, Аноним, Вы писали: А>Элементарно. А>1. Заведи MessageLoop в своём потоке. Создай в своём потоке WindowHandle и PeekMessage,GetMessage переодически А>2переодически вызываешь GetMessage или PeekMessage что бы проверить а не пришла какая-нибуть хрень
Спасибо, за советы..
Но, мне нужно получить именно событие..
То есть у меня во втором потоке организован прием данных.. и я на на нем могу зависать на некотрое время.. а по месаджу из основного потока хочу делать отправку данных.
А>3. Заведи ThreadSafeQueue и не пользуйся виндовыми подвисающими очередями событий :P
А можно поподробнее рассказать? что это за зверь? и как с ним работать?
Re[2]: Как обработать PostMessage в потоке TThread
Здравствуйте, MBo, Вы писали: MBo>У потока должна быть организована очередь сообщений. MBo>Для этого можно завести окно (AllocateHWND) и в его оконной функции ловить сообщения, или вовсе без окна — в начале работы потока вызвать PeekMessage (тогда организуется очередь), а потом в поточной функции проверять GetMessage (т.е. цикл выборки сообщений)
procedure TConnectionThread.Execute;
begin
H:=AllocateHWnd(MyCoolHandler);
Communication();
end;
Делаю в основном потоке:
PostMessage(MyConnectionThread.H,WM_MY,1,1) и/или PostMessage(MyConnectionThread.Handle,WM_MY,1,1)...
Но в процедура MyCoolHandler внутри потока никак не вызывается! что я сделал не так?
Подскажите пожалуйста!
В цикле запрашивать GetMessage.. для меня не решение так как хочу получить в потоке именно событие прихода сообщения.
Re[3]: Как обработать PostMessage в потоке TThread
Здравствуйте, DDDDD, Вы писали:
DDD>То есть у меня во втором потоке организован прием данных.. и я на на нем могу зависать на некотрое время.. а по месаджу из основного потока хочу делать отправку данных.
Скорее всего тебе не нужен PostMessage из основного потока в фоновый поток. В зависимости от задачи (несформулированной) нужна в либо булева переменная-флажок, выставляемая в основном потоке и проверяемая/сбрасываемая в фоновом потоке (возможно защищённая критической секцией) либо Event, сигнализируемый в основном потоке и отлавливаемый и сбрасываемый через WaitForMultipleObjects в фоновом потоке.
---
The optimist proclaims that we live in the best of all possible worlds; and the pessimist fears this is true
Re[3]: Как обработать PostMessage в потоке TThread
Здравствуйте, DDDDD, Вы писали:
DDD>Делаю в основном потоке: DDD> PostMessage(MyConnectionThread.H,WM_MY,1,1)
DDD>Но в процедура MyCoolHandler внутри потока никак не вызывается! что я сделал не так?
Не сделал цикл выборки сообщений. У тебя есть окно и оконная функция в потоке, но нет ничего для доставки сообщения в это окно.
---
The optimist proclaims that we live in the best of all possible worlds; and the pessimist fears this is true
Re[4]: Как обработать PostMessage в потоке TThread
Здравствуйте, wallaby, Вы писали: W>Скорее всего тебе не нужен PostMessage из основного потока в фоновый поток. В зависимости от задачи (несформулированной) нужна в либо булева переменная-флажок, выставляемая в основном потоке и проверяемая/сбрасываемая в фоновом потоке (возможно защищённая критической секцией) либо Event, сигнализируемый в основном потоке и отлавливаемый и сбрасываемый через WaitForMultipleObjects в фоновом потоке.
Формулирую задачу подробней:
Я хочу написать клиент на базе TIdTCPClient Indy 9. Так как в клиенте нету события получения даных, приходится делать бесконечный цикл по приему. Для того чтобы не загружать основной поток, TIdTCPClient вынес в другой поток.
Где делаю:
try
while TCPClient.Connected do
begin
if ThreadExitEvent then exit;
MyReadChar := TCPClient.ReadChar;
//некоторое количество кода..
end;
finally
TCPClient.Disconnect;
PostMessage(Form1.Handle,WM_MY,0,0);
end;
При получении данных читаю их, записываю в буфер и отправляю PostMessage основному потоку который уже производит обработку данных сигнализирует пользователю и тд и тп.. Буфер защищен критическими секциями..
По получению данных все супер, данные приходят, основной поток получает PostMessage..
Проблема в отправке!
Дело в том что второй поток если осутствует обмен висит на ReadChar.. Обмен не равномерем. возможны паузы до 60 с..
Проблема 1. Для того что бы завершить поток я использую булевскую переменную, но проверит поток ее состояние только когда придет следующий байт.. таким образом получается значительная задержка..
Проблема 2. Та же история только с отправкой! что более критично!
Задача получать события в втором потоке!!
Re[4]: Как обработать PostMessage в потоке TThread
W>>Не сделал цикл выборки сообщений. У тебя есть окно и оконная функция в потоке, но нет ничего для доставки сообщения в это окно.
DDD>А как его организовать? Нужен бесконечный цикл?
W>>Не сделал цикл выборки сообщений. У тебя есть окно и оконная функция в потоке, но нет ничего для доставки сообщения в это окно.
DDD>А как его организовать? Нужен бесконечный цикл? DDD>Если есть брость плз линку..
Че тут думать (это я со своей колокольни)
Вот как это делается:
const
MY_SOME_MESSAGE = WM_USER + 10;
type
TConnectionThread = class(TThread)
private
FMessageWindow : HWND;
FTerminateEvent : TSimpleEvent;
FStartEvent : TSimpleEvent;
procedure MessageWndProc(var Message: TMessage);
private
procedure MySomeMessageHandler(var Message: TMessage); message MY_SOME_MESSAGE;
protected
procedure Execute; override;
public
constructor Create;
destructor Destroy; override;
function PostMessage(Msg: UINT; wParam: WPARAM; lParam: LPARAM): BOOL;
procedure Terminate; reintroduce;
end;
implementation
constructor TConnectionThread.Create;
begin
inherited Create(True);
FStartEvent := TSimpleEvent.Create(nil, True, False, '');
FTerminateEvent := TSimpleEvent.Create(nil, True, False, '');
end;
destructor TConnectionThread.Destroy;
begin
inherited;
FStartEvent.Free;
FTerminateEvent.Free;
end;
procedure TConnectionThread.Execute;
const
MWMO_INPUTAVAILABLE = 4;
var
dwResult: Cardinal;
aEvent : THandle;
msg : TMsg;
quit : Boolean;
begin// окно должно быть создано в этом потоке
FMessageWindow := AllocateHWnd(MessageWndProc);
try
quit := False;
FStartEvent.SetEvent;
aEvent := FTerminateEvent.Handle;
while not Terminated and not quit do
begin
dwResult := MsgWaitForMultipleObjectsEx(1, aEvent, INFINITE, QS_ALLEVENTS, MWMO_INPUTAVAILABLE);
case dwResult of
WAIT_OBJECT_0:
begin// освободилось событиеend;
WAIT_OBJECT_0 + 1:
begin// в очереди появилось сообщение
// разослать все сообщенияwhile PeekMessage(msg, 0, 0, 0, PM_REMOVE) do
begin
if msg.message = WM_QUIT then
begin// сообщение WM_QUIT - выходим из цикла
quit := True;
end
else
begin// транслируем и пересылаем сообщение
TranslateMessage(&msg);
DispatchMessage(&msg);
end;
end;
// наша очередь пустаend;
end;
end;
finally
DeallocateHWnd(FMessageWindow);
end;
end;
procedure TConnectionThread.MessageWndProc(var Message: TMessage);
begin
Dispatch(Message);
Message.Result := DefWindowProc(FMessageWindow, Message.Msg, Message.WParam, Message.LParam);
end;
procedure TConnectionThread.MySomeMessageHandler(var Message: TMessage);
begin// ну что ж поймали наше событиеinherited;
end;
function TConnectionThread.PostMessage(Msg: UINT; wParam: WPARAM; lParam: LPARAM): BOOL;
begin
if FMessageWindow = 0 then
begin
if Suspended then
raise Exception.Create('Thread not started');
FStartEvent.WaitFor(INFINITE);
end;
Result := Windows.PostMessage(FMessageWindow, Msg, wParam, lParam);
end;
procedure TConnectionThread.Terminate;
begin
inherited Terminate;
FTerminateEvent.SetEvent;
end;
Здравствуйте, Jack128, Вы писали:
J>Здравствуйте, Danchik, Вы писали:
D>>Здравствуйте, DDDDD, Вы писали:
J>а зачем нужен FTerminateEvent если есть WM_QUIT по которому мы так и так должны выйти из потока ?
Согласен лишнее
Тогда хватит только GetMessage и на Terminate — PostMessage(WM_QUIT...)