首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >Delphi: PostThreadMessage & PeekMessage不工作

Delphi: PostThreadMessage & PeekMessage不工作
EN

Stack Overflow用户
提问于 2014-02-10 14:07:39
回答 2查看 2.4K关注 0票数 1

当我的主应用程序(Delphi2009)终止时,我想让它通知我的线程(定时器、带ADO连接的TDataModules、SMTP等)优雅地进行处理。

在我的主应用程序中,我有以下内容:

代码语言:javascript
代码运行次数:0
运行
复制
try
      PostThreadMessage(bpvccMAILER.ThreadID, WM_SYSTEM_CLOSE, self.Handle, 0);
      returnMessage := (SysErrorMessage(GetLastError)); //Returns 'The operation completed successfully'
    while TRUE do
            begin
                sleep(1000);
                if not (Assigned(bpvccMAILER)) then
                begin
                    bpvccACTIVITY_LOGGER.Write('SHUTDOWN','TBPVCommunicatorGUI.FormClose - All Threads have shut down');
                    break;
                end;
                locWaited := locWaited  + 10;
            end;  
        except
        end;
    finally
        FreeAndNil(bpvccACTIVITY_LOGGER);
        FreeAndNil(bpvccMAILER);
    end;

线程类:

代码语言:javascript
代码运行次数:0
运行
复制
TBPVMailer = class(TThread)
    protected
        SMTP       : TIdSMTP;
        interval   : Integer;
        fMain      : Integer;
        fMainIsSvc : Boolean;
        fTerminated: Boolean;
        function SendEmail(AEmail: TEmailObj) : TBPVEmailSendResult;
        function doSleep : Boolean;
        procedure Write(AStatus, AMessage : String);
        procedure FlushQueue();
        procedure HandleMessage(var Message : TMessage); message WM_SYSTEM_CLOSE;
    public
        constructor Create(AServer : String; APort : Integer; AUser, APass : String; AInterval : Integer; StartSuspended : Boolean); overload;
        procedure   Execute; override;
        procedure QueueEmail(AEmail: TEmailObj; EmailType : TBPVEmailType; AssociatedID : String);
        destructor Destroy; override;
end;

procedure TBPVMailer.HandleMessage(var Message: TMessage);
var
msg : tagMSG;
begin
  PeekMessage(&msg, 0, 0, 0, PM_NOREMOVE);
    fMain := Message.WParam;
    fMainIsSvc := Message.LParam = 1;
    fTerminated := TRUE;
end;

问题是,Assigned(bpvccMAILER)即使在调用PostThreadMessage之后也总是返回true。此外,bpvccMAILER.fTerminated始终为FALSE,这意味着永远不会执行TBPVMailer.HandleMessage,因为此时值被设置为TRUE。我做错了什么,我的线程似乎没有接收到消息?

EN

回答 2

Stack Overflow用户

发布于 2014-02-10 15:17:04

一个显而易见的解释是你的线程中没有消息泵。你发布了消息,但是线程并不抽取它的队列。

不过,代码是不必要的复杂。似乎根本不需要消息。调用线程的Terminate方法,然后使用它的WaitFor方法等待线程停止。或者更简单,只需在线程上调用Free

你的代码确实包含了一些奇怪的东西:

  • 为什么要调用PeekMessage?据我所知,那没有任何用处。应避免使用Sleep等待
  • 。您几乎总是可以使用专用的等待函数。
  • 奇怪的是,你要等到bpvccMAILERnil,然后再使用FreeAndNil(bpvccMAILER)
  • 只有在定义明确时才能调用GetLastError。通常情况下,这仅在前面的API调用失败时才会发生。并且失败由API调用返回的值指示。
票数 4
EN

Stack Overflow用户

发布于 2017-05-11 01:04:38

只需调用PostThreadMessage并返回,之后不会有任何睡眠循环。

如果您需要等到bpvccMAILER完成,可以添加代码,在完成时向主线程发送一个PostMessage。因此,主线程将处理此消息,并将意识到辅助线程已完成。从一开始就以这种方式更改您的应用程序可能并不容易,但渐渐地,您将以这样一种方式设计应用程序,即始终执行正确的线程处理。

除此之外,如果你使用PostThreadMessage,那么你的Thread.Execute循环必须有MsgWaitForMultipleObjects。

下面是一个关于Thread.Execute循环的例子:

代码语言:javascript
代码运行次数:0
运行
复制
<skipped>
repeat
  <skipped>
  R := MsgWaitForMultipleObjects(EventCount, EventArray, False, INFINITE, QS_ALLINPUT);
  <skipped>
  if R = WAIT_OBJECT_0 + EventCount then
  begin
    while PeekMessage(M, 0, 0, 0, PM_REMOVE) do
    begin
      if M.Message = WM_QUIT then
        Break;
      TranslateMessage(M);
      DispatchMessage(M);
    end;
    if M.Message = WM_QUIT then
      Break;
  end;
  <skipped>
until Terminated;
<skipped>

如果应用程序最终需要在踏步运行时退出(假设线程对象在T变量中),请执行以下操作:

代码语言:javascript
代码运行次数:0
运行
复制
T.Terminate;
SetEvent([one of the event of the EventArray]); // we should call it AFTER terminate for the Terminated property would already be True when the tread exits from MsgWaitForMultipleObjects
T.WaitFor; 
T.Free; // "Free" calls "WaitFor" anyway, but Remy Lebeau suggests to explicitly call "WaitFor" before "Free".
T := nil;
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/21670162

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档