Как обработать PostMessage в потоке TThread
От: DDDDD  
Дата: 30.03.10 09:25
Оценка:
Подскажите как обработать PostMessage в потоке.
У меня есть поток:
MyConnectionThread : TConnectionThread;

type
TConnectionThread = class(TThread)
procedure MyCoolHandler(var MyMessage: TMessage); message WM_MY;
private
{ Private declarations }
protected
procedure Execute; override;
end;

Если я в Execute отправляю PostMessage форме ( PostMessage(Form1.Handle,WM_MY,2,1) то форма его получает.

Но не получается обратно! то есть вопрос как из основного потока передать сообщение и обработать его внутри потока?

Пробовал PostThreadMessage(GetWindowThreadProcessId(MyConnectionThread.Handle),WM_MY,1,1) — эффекта ноль..
Re: Как обработать PostMessage в потоке TThread
От: MBo  
Дата: 30.03.10 09:49
Оценка:
Здравствуйте, 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
От: DDDDD  
Дата: 30.03.10 12:57
Оценка:
Здравствуйте, Аноним, Вы писали:
А>Элементарно.
А>1. Заведи MessageLoop в своём потоке. Создай в своём потоке WindowHandle и PeekMessage,GetMessage переодически
А>2переодически вызываешь GetMessage или PeekMessage что бы проверить а не пришла какая-нибуть хрень

Спасибо, за советы..
Но, мне нужно получить именно событие..
То есть у меня во втором потоке организован прием данных.. и я на на нем могу зависать на некотрое время.. а по месаджу из основного потока хочу делать отправку данных.

А>3. Заведи ThreadSafeQueue и не пользуйся виндовыми подвисающими очередями событий :P

А можно поподробнее рассказать? что это за зверь? и как с ним работать?
Re[2]: Как обработать PostMessage в потоке TThread
От: DDDDD  
Дата: 30.03.10 14:38
Оценка:
Здравствуйте, MBo, Вы писали:
MBo>У потока должна быть организована очередь сообщений.
MBo>Для этого можно завести окно (AllocateHWND) и в его оконной функции ловить сообщения, или вовсе без окна — в начале работы потока вызвать PeekMessage (тогда организуется очередь), а потом в поточной функции проверять GetMessage (т.е. цикл выборки сообщений)

Спасибо, за совет..
Я сделал следующие:

type
TConnectionThread = class(TThread)
H : THandle;
procedure MyCoolHandler(var MyMessage: TMessage);
private
{ Private declarations }
protected
procedure Execute; override;
end;


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
От: wallaby  
Дата: 30.03.10 14:47
Оценка:
Здравствуйте, 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
От: wallaby  
Дата: 30.03.10 15:52
Оценка:
Здравствуйте, 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
От: DDDDD  
Дата: 30.03.10 21:42
Оценка:
Здравствуйте, 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
От: DDDDD  
Дата: 30.03.10 21:45
Оценка:
W>Не сделал цикл выборки сообщений. У тебя есть окно и оконная функция в потоке, но нет ничего для доставки сообщения в это окно.

А как его организовать? Нужен бесконечный цикл?
Если есть брость плз линку..
Re[5]: Как обработать PostMessage в потоке TThread
От: wallaby  
Дата: 31.03.10 09:30
Оценка:
Здравствуйте, DDDDD, Вы писали:


W>>Не сделал цикл выборки сообщений. У тебя есть окно и оконная функция в потоке, но нет ничего для доставки сообщения в это окно.


DDD>А как его организовать? Нужен бесконечный цикл?


Пользуйтесь поиском, в том числе по этому сайту — http://rsdn.ru/forum/delphi/883505.aspx
Автор: Leonid Troyanovsky
Дата: 04.11.04
---
The optimist proclaims that we live in the best of all possible worlds; and the pessimist fears this is true
Re[5]: Как обработать PostMessage в потоке TThread
От: Danchik Украина  
Дата: 31.03.10 10:59
Оценка:
Здравствуйте, DDDDD, Вы писали:


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;


Тестируем

procedure TForm1.Button1Click(Sender: TObject);
var
  aThread : TConnectionThread;
begin
  aThread := TConnectionThread.Create;
  aThread.FreeOnTerminate := True;
  aThread.Resume;
  aThread.PostMessage(MY_SOME_MESSAGE, 0, 0);

  Sleep(1000);

  aThread.Terminate;
  aThread.WaitFor;
end;


Где то как то так
Re[6]: Как обработать PostMessage в потоке TThread
От: Jack128  
Дата: 31.03.10 18:43
Оценка:
Здравствуйте, Danchik, Вы писали:

D>Здравствуйте, DDDDD, Вы писали:


а зачем нужен FTerminateEvent если есть WM_QUIT по которому мы так и так должны выйти из потока ?
Re[7]: Как обработать PostMessage в потоке TThread
От: Danchik Украина  
Дата: 01.04.10 12:19
Оценка:
Здравствуйте, Jack128, Вы писали:

J>Здравствуйте, Danchik, Вы писали:


D>>Здравствуйте, DDDDD, Вы писали:


J>а зачем нужен FTerminateEvent если есть WM_QUIT по которому мы так и так должны выйти из потока ?


Согласен лишнее

Тогда хватит только GetMessage и на Terminate — PostMessage(WM_QUIT...)
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.