///////////////////////////////////////////
1。“一个进程只有一个消息队列,无论进程创建了多少线程”----对嘛??2。getmessage的参数只能指定窗口句柄,那么得到的是整个应用程序里面那个窗口的消息还是属于本线程所创建的handle匹配的窗口?
如果时后者,那么创建窗口的时候createwindowex函数好像没有规定线程id!3。如果用peekmessage如何?4。application.processmessages又如何?
下面是代码:在一个线程execute的时候创建一个窗体,///////////////////////////
unit Main;//主窗体单元。interfaceuses
  Windows,wndthreadunit, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;var
  Form1: TForm1;implementation{$R *.dfm}procedure TForm1.Button1Click(Sender: TObject);
var
t:TWndThread;
begin
  t:=TWndThread.Create(false);end;end.
/////////////////////////////
unit wndthreadunit;//线程单元。interfaceuses
  Classes,windows,forms,controls;type
  TWndThread = class(TThread)
  private
    { Private declarations }
    form:tform;
  protected
    procedure Execute; override;
  public
   constructor Create(ASuspend:boolean);  
  end;implementation{ WndThread }constructor TWndThread.Create(ASuspend: boolean);
begin
  inherited create(asuspend);
end;procedure TWndThread.Execute;
var
msg:tmsg;
begin
  form:=tform.Create(nil);
  form.Left:=0;
  form.Top:=0;
  form.Width:=300;
  form.Height:=100;
  form.Caption:='Thread Form';
  form.Show;  while not terminated do
  begin
    //application.ProcessMessages; 去掉注释,注释下面三行也不会有问题。
    getMessage(Msg, form.Handle, 0, 0);
    translatemessage(msg);
    dispatchmessage(msg);  end;end;end.
//////////////////////////////////////////////////////

解决方案 »

  1.   

    1、系统为每个生成的线程创建一个消息队列,即线程有自己的消息队列(当线程调用了WIN32 USER/GDI的函数时候创建线程)
    2、线程有自己的消息队列,在消息循环
        getMessage(Msg, form.Handle, 0, 0);
        translatemessage(msg);
        dispatchmessage(msg);
    中getMessage得到的当然是自己线程的消息
    3、getMessage和PekkMessage当然是有区别的,如果消息队列里没有消息,PeekMessage就会返回FALIE,不会等待继续获取消息;而GetMessage则会一直等待消息队列,等到里面有消息为止,才返回。
    4、所以,如果你用getMessage(Msg, form.Handle, 0, 0)取得消息,application.ProcessMessages最好能用上,它可以强制一个消息,因为如果没有取得消息的话,getMessage就会一直等待消息。虽然你的程序没有错:)
    以上仅是我对消息运行机制的一点理解。    
      

  2.   

    如果你一定要去掉application.ProcessMessages,你就用PeekMessage来获取消息
      

  3.   

    (当线程调用了WIN32 USER/GDI的函数时候创建线程的消息队列)
      

  4.   

    To:cg1120(代码最优化-§志不强者智不达§)
    好棒!拍马屁中。
    To:  stanely (俺是邢她汉子)  
    我认为线程中带Form总是不太好吧,我认为线程一般是用来进行大量数据的并行辅助运算。一个主进程中有多个线程Form同时运行,你用没有试过线程同步?(我试过,效果不理想)。
    帮你up
      

  5.   

    这也是一个偶然的机会想起来的问题,
    目的不是要在线程里面实现什么,就是想借助这个例子,高明白windows 消息机制。
      

  6.   

    to 代码最优化:
    “如果你一定要去掉application.ProcessMessages,你就用PeekMessage来获取消”。
    我曾经式过,但是会出现问题,只能用getmessage那套组合。。不知道为什么:    peekMessage(Msg, form.Handle, 0, 0);
        translatemessage(msg);
        dispatchmessage(msg);
    /////////////////////
    另外,    getMessage(Msg, form.Handle, 0, 0);
        translatemessage(msg);
        dispatchmessage(msg);
    不要translatemessage(msg);仿佛也可以。不知道为什么??
      

  7.   

    我看了application.processesmessages的代码,就是peekmessage,但是applicaton既然是实际的主窗体,那么也只是一个窗体而已。那么他怎么peek到的整个进程中所有线程的消息呢?
    还有,如果消息是队列跟线程一一对应的,那么如果我要给一个工作线程发消息,用什么?
    sendmessage?那么句柄是谁呢?谢谢!
      

  8.   

    我也看了看delphi的APPLICATION处理消息的源码,它是这样的:
    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;
    PeekMessage(Msg, 0, 0, 0, PM_REMOVE),它有五个参数,如果你要知道PM_REMOVE和PeekMessage里参数的意思,可以云看看MSDN。
    如果你不要translatemessage(msg)当然可以运行程序,但用来“派送消息”的函数都没有,你的消息循环做来干什么?
    DELPHI中的大部份VCL是线程不安全的,为此Borland为线程提供了一个Synchronize函数来处理消息,当然你也可以自己做,用SendMessage来实现,句柄是你的线程窗口句柄,不过用PostMessage来发送消息是不行的。你可以试试
      

  9.   

    procedure TWndThread.Execute;
    var
    msg:tmsg;
    begin
      form:=tform.Create(nil);
      form.Left:=0;
      form.Top:=0;
      form.Width:=300;
      form.Height:=100;
      form.Caption:='Thread Form';
      form.Show;  while not terminated do
      begin
        //application.ProcessMessages; 去掉注释,注释下面三行也不会有问题。
        getMessage(Msg, form.Handle, 0, 0);
        translatemessage(msg);
        dispatchmessage(msg);  end;
    以上程序中的消息循环是你自己线程的消息循环,不知道你是否这样认为
      

  10.   

    版主兄,我是说translatemessage可以不用,但是dispatchmessage要用啊。因为我试验过,去掉translatemessage也没有什么不一样的阿。confused...
      

  11.   

    PeekMessage只能取当前线程里面的消息,所以Form.Handle的消息它是取不了的,正在想...
      

  12.   

    还有,如果消息是队列跟线程一一对应的,那么如果我要给一个工作线程发消息,用什么?
    sendmessage?那么句柄是谁呢?SendMessage的句柄当然是0了,也可以用postthreadmessage了。
    看看msdn吧。delphi fans也可以看看嘛
      

  13.   

    楼上不对:
    进程建立了一个主线程,一个线程拥有一个消息队列,所以在主线程中的ProcessMessages可以通过: PeekMessage进行取发给这个线程的消息
     如果你建立的线程需要建立消息队列,这样做:
       PeekMessage(msg, 0, 0, 0, PM_NOREMOVE);
     参数: PeekMessage的PM_NOREMOVE就是创建一个消息队列,help写的很明白,PeekMessage即可以从消息队列中取消息也可以创建消息队列,关键就是:PM_REMOVE, 和 PM_NOREMOVE,记住,在自已的线程创建消息队列必须在线程的运行中进行,即:
    procedure TMyThread.Execute;
    begin
      PeekMessage(msg, 0, 0, 0, PM_NOREMOVE);
      ...
         while PeekMessage(msg, 0, 0, 0, PM_REMOVE) do
           DispatchMessage(msg); //
    end;
      

  14.   

    哦,主线程或其它线程与建立了消息队列的线程是这样通讯的:
      PostThreadMessage(MyThread.ThreadID, WM_MyMsg, wParam, lParam);也就是PostThreadMessage, 那个Handle参数是消息队列线程的ThreadID,记住这很重要。
      

  15.   

    木石三说得没错!
    "版主兄,我是说translatemessage可以不用,但是dispatchmessage要用啊。
    因为我试验过,去掉translatemessage也没有什么不一样的阿。"
    不好意思,看错函数了,但不管你的程序是否编译通过,没有正确的消息循环,你是得到不你要获取的线程消息的。
    如果楼主要得到更多的线程方面的东西,请参看北京大学出版社《Windows程序设计》
      

  16.   

    木石三兄说得是没错.
    我觉得我也没错吧,难道sendmessage(0,....)不给线程,  我去看看msdn先