加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Java > 正文

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

发布时间:2020-12-14 23:57:49 所属栏目:Java 来源:网络整理
导读:我有一个Delphi 6应用程序,它有一个专用于与使用SendMessage()和WM_COPYDATA消息与外部程序连接的外部应用程序进行通信的线程.因此,我使用AllocateHWND()创建一个隐藏窗口来满足此需求,因为由于SendMessage()函数只接受窗口句柄而不是线程ID,因此线程消息队
我有一个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}

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读