无法捕捉消息(postmessage)

时间:2013-11-14 12:49:49

标签: delphi

我想将postmessage()的消息发送到TObject实例,但是在线程终止后,程序不会进入方法HandleThreadCompletion。

const
  WM_THREAD_COMPLETE = WM_USER + 5437;

TObject实例(TMaster)包含线程对象的标识符

type
  TMaster = class(TObject)
  private
    ...
    Fslave_search_thread : Tsrch_slave_thread;
    fMsgHandlerHWND : HWND;
    function start_slvsearch_th: integer; 
    procedure HandleThreadCompletion(var Message: TMessage);
    ...
  public
    ...
  end;

constructor TMaster.Create (aNode: TTreeNode; aName, anIP, aMAC: string);
begin
  ...
  fMsgHandlerHWND := AllocateHWnd(HandleThreadCompletion);
  ...
end;

我在TMaster.HandleThreadCompletion()

中释放并取消线程
procedure TMaster.HandleThreadCompletion(var Message: TMessage);
begin
  if message.msg = WM_THREAD_COMPLETE then begin
    if Assigned(Fslave_search_thread) then
    begin
      Fslave_search_thread.WaitFor;
      Fslave_search_thread.Free;
      Fslave_search_thread := nil;
      ...
    end
  end else
    message.result := DefWindowProc(fMsgHandlerHWND, Message.Msg, Message.wParam, Message.lParam) ; 
end;

在这里创建线程(暂停),填写一些字段而不是启动它(恢复)。

function TMaster.start_slvsearch_th: integer;
var
  i: integer;
begin
  if not Assigned(Fslave_search_thread) then begin
    ...
    Fslave_search_thread := Tsrch_slave_thread.Create(true);
    ... 
  with Fslave_search_thread do
  begin
    master := self;
    master_HWND := self.fMsgHandlerHWND;
    FreeOnTerminate := False;
    Resume;   
    ...
  end;
end;

终止时(从外部设置终止标志或循环结束),发送消息:

procedure Tsrch_slave_thread.Execute;
begin
  while master.CMD_LISTCNT = 1 do 
  begin 
    ...
    if terminated then break;
  end;
  PostMessage(master_HWND, WM_THREAD_COMPLETE, 0, 0);   
  ...
end;

http://members.upclive.hu/ikt/thread_terminate_test_postmessage.zip

2 个答案:

答案 0 :(得分:1)

最明显的解释是:

  1. 主线程已终止,然后才能处理该消息。
  2. 主线程没有抽取其消息队列。
  3. 主线程在处理消息之前销毁窗口。
  4. 如果您展示了SSCCE,我可以进一步缩小它。由于我们看不到SSCCE,这意味着你需要缩小它。

答案 1 :(得分:1)

<强>更新

Sertac找到了解决问题的原因。 fMsgHandlerHWNDtry/finally构造中创建后应立即销毁try/except,该构造应为OnTerminate(或其他内容)。

无论如何,我的答案的其余部分不太容易实现。


如果没有产生观察结果的测试用例,很难说你的代码有什么问题。

但是,我建议使用更简单的方法来处理线程关闭。

在启动线程之前,为TThread.FreeOnTerminate属性分配一个事件处理程序。 通过设置OnTerminate,您不必显式释放线程对象。

type TMaster = class private FThread: TMyThread; procedure OnThreadTerminate(Sender: TObject); public constructor Create; procedure StopThread; function StartThread: Boolean; end; constructor TMaster.Create; begin Inherited; FThread := Nil; end; procedure TMaster.StopThread; begin if Assigned(FThread) then FThread.Terminate; end; procedure TMaster.OnThreadTerminate(Sender: TObject); begin // Collect data from the thread ... // Just clear the thread reference FThread := Nil; end; function TMaster.StartThread: Boolean; begin Result := (FThread = Nil); if Result then begin FThread := TMyThread.Create(True); FThread.FreeOnTerminate := True; // Thread will self destruct FThread.OnTerminate := Self.OnThreadTerminate; // Called when thread is terminating FThread.Start; // Older Delphi versions uses Resume end; end; 事件处理程序中,只需从线程中收集数据(如果有的话),并将线程引用设置为nil。

{{1}}