不知道是否可以这样理解:
    我把Button1Click函数看成是整个主线程回调函数的一部分,当Button1Click没返回的时候,也就是说主线程的回调函数没返回,主线程无法响应主线程登记消息队列中下一条消息的,鉴于DELPHI中有ProcessMessages这招,看下ProcessMessages里面的代码,居然是一套消息循环机制,在线程内再建立一个消息循环系统?我的理解是主线程中已经有Application.Run内建的消息循环机制了,现在在回调函数之内再建立一个消息循环机制?是不是之后所有的消息循环都会在ProcessMessages里面处理,而不在Application.Run里面处理?还是有其他理解?
    另外参考代码中,我把Application.ProcessMessages;注释掉程序进入死循环无法响应任何消息,这个能理解。但是当我把Application.ProcessMessages;启用起来,我可以拖动窗口,能很快刷新出来,这个正是DELPHI的出发点,也能理解,但是我再点击这个Button1Click,注意到因为有ProcessMessages作用,程序会响应我的Button1Click,代码会重入到Button1Click中,不奇怪吗?如果我还点,还点… 那要重入多少次?单线程内该代码多次重入并且每部分代码都有一个消息循环,并且死循环一直都在?
    好像是有个术语叫“接管消息机制”,在Form.ShowModal中就是这样的吧?我的理解有很多不对的地方,希望各位能够指出,因为一切实在是太费解了… 现在我想知道的是Application.ProcessMessages 和 Application.Run是如何协作工作的?另外Form.ShowModal 和 Application.Run又是如何协作的呢?参考代码:var
  Busy: Boolean;
  ExitFlag: Boolean;procedure TForm1.Button1Click(Sender: TObject);
begin
  if Busy then Exit;
  //Busy := true;  //这行去掉不要
  while true do
  begin
    Application.ProcessMessages;  //
    if ExitFlag then Break;
  end;
  Busy := false;
end;procedure TForm1.Button2Click(Sender: TObject);
begin
  ExitFlag := true;
end;

解决方案 »

  1.   

    你重入的代码都进入Application.ProcessMessages这个函数里,有点像递归,上一层的循环已经被阻塞了。
      

  2.   

    Application.ProcessMessages是分发主线程的消息,楼主的这个问题是典型的消息重入,应该避免这种问题,用线程可以解决这种问题。另外消息循环是针对线程的。
      

  3.   

    恩 好像是这么一回事,但是Application.ProcessMessages内建的消息循环呢?我还是不大好理解?
    是不是说之后的所有消息都会在Application.ProcessMessages中处理,直到该重入代码全部处理完毕?
      

  4.   

    当你在某一个消息处理过程当中使用了Application.ProcessMessage之类就会导致消息重入,即前一个消息还没有处理完,而进入到了下一个消息的处理过程当中,此时就有可能导致后面的消息处理例程破坏掉前一个消息处理例程的“现场”。
      

  5.   

    procedure TApplication.ProcessMessages;
    var
      Msg: TMsg;
    begin
      while ProcessMessage(Msg) do {loop};
    end;function TApplication.ProcessMessage(var Msg: TMsg): Boolean;
    var
      Handled: Boolean;
    begin
      Result := False;
      if PeekMessage(Msg, 0, 0, 0, PM_REMOVE) then
      begin
        Result := True;
        if Msg.Message <> WM_QUIT then
        begin
          Handled := False;
          if Assigned(FOnMessage) then FOnMessage(Msg, Handled);
          if not IsHintMsg(Msg) and not Handled and not IsMDIMsg(Msg) and
            not IsKeyMsg(Msg) and not IsDlgMsg(Msg) then
          begin
            TranslateMessage(Msg);
            DispatchMessage(Msg);
          end;
        end
        else
          FTerminate := True;
      end;
    end;消息循环本来是Delphi维护处理的,而你进入死循环后,原来由Delphi处理的消息循环被阻塞,现在由你自己调用消息处理函数。PeekMessage,TranslateMessage,DispatchMessage。
      

  6.   

    谢谢各位的讲解,我想已经没什么疑问了,真是天下本无事,庸人自扰之,还有一点不是很明白的:Q:进入Button1Click的死循环之后,我没有再点击Button1Click,避免了Button1Click代码的重入,这时候由Button1Click中的ProcessMessages接管了主线程的消息循环,凡是在该主线程中发生的其他任何消息都会经过ProcessMessages中的DispatchMessage,在这之后都能顺利分发并且执行相应回调,当主线程登记消息队列中再没有其他的消息到来的时候,主线程会继续死循环,但是由于还是在死循环,就是说之前的Button1Click还没有返回,系统就已经处理了主线程登记消息队列中其他后面到来的的消息,那么这个主线程登记消息队列中消息的处理顺序是不是先后顺序有所改变,这个怎么理解?
      

  7.   

    个人觉得这2句话有问题:
    1.凡是在该主线程中发生的其他任何消息都会经过ProcessMessages中的DispatchMessage
    //消息分为队列消息与非队列消息!只有发送到系统消息队列的消息(用PostMessage),才通过主线程的消息泵来GetMessage和DispatchMessage,其它的一些消息直接发送到窗口函数上(SendMessage),由于SendMessage属于阻塞式处理,所以一个消息处理不完毕,会阻塞整个消息队列!
    2.当主线程登记消息队列中再没有其他的消息到来的时候,主线程会继续死循环,但是由于还是在死循环
    当主线程的消息队列中没有消息时,GetMessage所在线程会处于sleep状态
      

  8.   

    就是递归呗,有啥不好理解的,继续点下去就stack overflow呗
      

  9.   

    发送到窗口的消息也是经过消息队列发布的。
    ----------------------------------
    好像不是吧
    About Messages and Message Queues 
      

  10.   

    Nonqueued messages are sent immediately to the destination window procedure, bypassing the system message queue and thread message queue
      

  11.   

    To Seamour:
    哈哈,我才小星星一个,哪能跟你们超星级别的比啊!不过还是谢谢你们!liangpei2008:
    谢谢你的指正!
      

  12.   


    POSTMESSAGE发送的才经过消息队列吧
      

  13.   

    1)队列消息(Queued Messages) 消息会先保存在消息队列中,消息循环会从此队列中取消息并分发到各窗口处理如鼠标,键盘消息。2) 非队列消息(NonQueued Messages)消息会绕过系统消息队列和线程消息队列直接发送到窗口过程被处理如: WM_ACTIVATE, WM_SETFOCUS, WM_SETCURSOR, WM_WINDOWPOSCHANGED 注意: postMessage发送的消息是队列消息,它会把消息Post到消息队列中; SendMessage发送的消息是非队列消息, 被直接送到窗口过程处理当一个线程向该线程所建立的窗口SendMessage消息时,它只是调用指定窗口的消息处理过程,并不将消息入队列 当一个线程向另一个线程所建立的窗口SendMessage时,该消息要追加到接收消息线程的发送消息队列,然后发送消息的线程进入等待状态,接收消息的线程处理完该消息后,由系统唤醒发送消息的线程,这时发送线程继续进行