多线程 – 具有隐藏窗口的线程的线程消息循环?

前端之家收集整理的这篇文章主要介绍了多线程 – 具有隐藏窗口的线程的线程消息循环?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我有一个Delphi 6应用程序,它有一个专用于与使用SendMessage()和WM_COPYDATA消息与外部程序连接的外部应用程序进行通信的线程.因此,我使用AllocateHWND()创建一个隐藏窗口来满足此需求,因为由于SendMessage()函数只接受窗口句柄而不是线程ID,因此线程消息队列将无法工作.我不确定的是在线程Execute()方法中放入什么.

我假设如果我使用GetMessage()循环或创建一个带有WaitFor *()函数的循环调用,那么线程将阻塞,因此线程的WndProc()永远不会处理来自外部程序的SendMessage()消息对?如果是这样,放入Execute()循环的正确代码是什么,它不会不必要地消耗cpu周期,但是一旦收到WM_QUIT消息就会退出?如果有必要,我总是可以使用Sleep()循环,但我想知道是否有更好的方法.

解决方法

AllocateHWnd()(更具体地说,MakeObjectInstance())不是线程安全的,所以你必须小心它.最好直接使用CreatWindow / Ex()(或者像 DSiAllocateHwnd()一样使用AllocateHWnd()的线程安全版本.

在任何情况下,HWND都与创建它的线程上下文绑定,因此您必须在Execute()方法中创建和销毁HWND,而不是在线程的构造函数/析构函数中.此外,即使使用SendMessage()向您发送消息,它们也来自另一个进程,因此在其拥有的线程执行消息检索操作之前,HWND不会处理它们,因此该线程需要自己的消息循环.

您的Execute()方法应如下所示:

procedure TMyThread.Execute;
var
  Message: TMsg;
begin
  FWnd := ...; // create the HWND and tie it to WndProc()...
  try
    while not Terminated do
    begin
      if MsgWaitForMultipleObjects(0,nil^,False,1000,QS_ALLINPUT) = WAIT_OBJECT_0 then
      begin
        while PeekMessage(Message,PM_REMOVE) do
        begin
          TranslateMessage(Message);
          DispatchMessage(Message);
        end;
      end;
    end;
  finally
    // destroy FWnd...
  end;
end;

procedure TMyThread.WndProc(var Message: TMessage);
begin
  if Message.Msg = WM_COPYDATA then
  begin
    ...
    Message.Result := ...;
  end else
    Message.Result := DefWindowProc(FWnd,Message.Msg,Message.WParam,Message.LParam);
end;

或者:

// In Delphi XE2,a virtual TerminatedSet() method was added to TThread,// which is called when TThread.Terminate() is called.  In earlier versions,// use a custom method instead...

type
  TMyThread = class(TThread)
  private
    procedure Execute; override;
    {$IF RTLVersion >= 23}
    procedure TerminatedSet; override;
    {$IFEND}
  public
    {$IF RTLVersion < 23}
    procedure Terminate; reintroduce;
    {$IFEND}
  end;

procedure TMyThread.Execute;
var
  Message: TMsg;
begin
  FWnd := ...; // create the HWND and tie it to WndProc()...
  try
    while not Terminated do
    begin
      if WaitMessage then
      begin
        while PeekMessage(Message,PM_REMOVE) do
        begin
          if Message.Msg = WM_QUIT then Break;
          TranslateMessage(Message);
          DispatchMessage(Message);
        end;
      end;
    end;
  finally
    // destroy FWnd...
  end;
end;

{$IF RTLVersion < 23}
procedure TMyThread.Terminate;
begin
  inherited Terminate;
  PostThreadMessage(ThreadID,WM_QUIT,0);
end;
{$ELSE}
procedure TMyThread.TerminatedSet;
begin
  PostThreadMessage(ThreadID,0);
end;
{$IFEND}
原文链接:https://www.f2er.com/java/127081.html

猜你在找的Java相关文章