Delphi线程没有收到消息

时间:2016-10-12 14:59:07

标签: multithreading delphi vcl

我正在使用多线程(RAD Studio XE5)开发应用程序。在应用程序开始时,我创建了一个单独的线程,只要主表单生效,它就会生效。

我能够将消息从线程发送到我的应用程序中创建的任何表单,但是我无法找到相反的方法,从主VCL线程向工作线程发送消息。 / p>

创建主表单时,我创建工作线程并将句柄复制到公共变量中:

  serverThread := TMyThread.Create(True, ServerPort + 1);
  serverThreadHandle := serverThread.Handle; // SAVE HANDLE
  serverThread.Start;

然后(从另一种形式FrmSender)我向线程发送一条消息:

  PostMessage(uMain.serverThreadHandle, UM_LOC_VCLMSG, UM_LOC_VCLMSG, Integer(PStrListVar));

这是线程的执行程序:

procedure TMyThread.Execute;
var
    (..)
    vclMSG : TMsg;
    str1, str2 : string;
    (..)
begin
    while not(Terminated) do
    begin
        Sleep(10);
        if Assigned(FrmSender) then
          if FrmSender.HandleAllocated then
            if PeekMessage(vclMSG, FrmSender.Handle, 0, 0, PM_NOREMOVE) then
              begin
                if vclMSG.message = UM_LOC_VCLMSG then
                  begin
                    try
                      pStrListVar := pStrList(vclMSG.lParam);
                      str1 := pStrListVar^.Strings[0];
                      str2 := pStrListVar^.Strings[1];
                    finally
                      Dispose(pStrListVar);
                    end;
                  end;
              end;  
        (.. do other stuff ..)
    end;
end;

然而 PeekMessage()永远不会返回true,就像它从未收到任何消息一样。我已经尝试将参数更改为 PeekMessage()

PeekMessage(vclMSG, 0, 0, 0, PM_NOREMOVE);

但没有结果。 有什么想法吗?

2 个答案:

答案 0 :(得分:5)

PeekMessage(vclMSG, FrmSender.Handle, 0, 0, PM_NOREMOVE)

第二个参数表示您只会检索发送给发件人的邮件FrmSender.Handle。但您已将邮件发送给收件人uMain.serverThreadHandle。这是PeekMessage永远无法返回的原因之一。

正如您所做的那样从线程访问VCL是错误的。表单的句柄需要重新创建VCL窗口,并且HandleAllocatedHandle上有明显的竞争。因此,即使你需要知道FrmSender.Handle,在线程中提出它也是错误的。

您实际上是将消息发送到线程句柄而不是窗口句柄。这意味着永远不会发送消息,这是PeekMessage无法返回的另一个原因。如果您在调用PostMessage时检查了返回值,那么您就可以了解到这一点。

我使用PostThreadMessage,或者通过调用AllocateHWnd将消息发布到线程中分配的窗口。

一旦您设法实际发送消息,使用PM_NOREMOVE意味着消息队列永远不会被清空。

您对Sleep的使用对我来说非常可疑。为什么不使用GetMessage并阻止消息到达。只要您看到Sleep的来电,就会非常怀疑。

您对Integer的强制转换将导致64位构建中的指针截断。要投射到的正确类型是LPARAM

我预计会有其他错误,这些只是我在2分钟快速扫描中看到的错误。

答案 1 :(得分:5)

来自MSDN PostMessage function documentation

  

在与创建指定窗口的线程关联的消息队列中放置(发布)消息,并返回而不等待线程处理消息。

     

要在与线程关联的消息队列中发布消息,请使用PostThreadMessage函数。

因此,您应该使用PostThreadMessage

  

将消息发布到指定线程的消息队列。它返回而不等待线程处理消息。

特别注意备注部分。收件人线程需要一个消息队列。按照以下步骤强制线程有一个:

  • 创建一个事件对象,然后创建该线程。
  • 使用WaitForSingleObject功能等待事件设置为 在致电PostThreadMessage之前发出信号状态。
  • 在邮件将发布到的帖子中,如此处所示调用PeekMessage以强制系统创建邮件队列。

    PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE)
    
  • 设置事件,以指示该事件 线程已准备好接收发布的消息。

然后,当使用PeekMessage时,您将句柄值-1传递给函数,如文档所述。