Delphi 线程未收到消息

Delphi thread not receiving messages

我正在开发一个多线程应用程序 (RAD Studio XE5)。在应用程序开始时,我创建了一个与主窗体一样长的线程。

我能够将消息从线程分派到在我的应用程序中创建的任何表单,但是我找不到相反的方法,即从主 VCL 线程向工作线程发送消息.

创建主窗体时,我创建工作线程并将句柄复制到 public 变量中:

  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() 永远不会 returns 真,就好像它从未收到任何消息一样。我尝试将参数更改为 PeekMessage():

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

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

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

第二个参数表示您将只检索发送给发件人 FrmSender.Handle 的邮件。但是您将邮件发送给了收件人 uMain.serverThreadHandle。这就是 PeekMessage 永远无法 return.

的原因之一

像你这样从线程访问VCL是错误的。窗体的句柄受 VCL window 重新创建的约束,并且在 HandleAllocatedHandle 上存在明显的竞争。所以即使你需要知道FrmSender.Handle,在线程中询问它也是错误的。

您实际上是将消息发送到线程句柄而不是 window 句柄。这意味着消息甚至从未发送过,这是 PeekMessage 不能 return 的另一个原因。如果您在调用 PostMessage 时检查了 return 值,您就会了解到这一点。

我会使用 PostThreadMessage 或 post 将消息发送到线程中分配的 window 并调用 AllocateHWnd.

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

我觉得你对 Sleep 的使用很可疑。为什么不使用 GetMessage 等阻塞直到消息到达。任何时候看到对 Sleep 的调用,都要非常怀疑。

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

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

来自 MSDN PostMessage function documentation:

Places (posts) a message in the message queue associated with the thread that created the specified window and returns without waiting for the thread to process the message.

To post a message in the message queue associated with a thread, use the PostThreadMessage function.

因此,您应该使用 PostThreadMessage:

Posts a message to the message queue of the specified thread. It returns without waiting for the thread to process the message.

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

  • 创建事件对象,然后创建线程。
  • 使用WaitForSingleObject函数等待事件设置为 调用 PostThreadMessage.
  • 之前的信号状态
  • 在消息将发布到的线程中,调用PeekMessage,如下所示,强制系统创建消息队列。

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

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