子线程给主线程发送没有问题,但反过来,行吗?,我试了试,好像没有作用!请教高手指点!谢谢

解决方案 »

  1.   

    你要在線程中實現消息循環, 自己接收消息要使用:BOOL PostThreadMessage(    DWORD idThread, // thread identifier
        UINT Msg, // message to post
        WPARAM wParam, // first message parameter
        LPARAM lParam  // second message parameter
       );
      

  2.   

    PeekMessage就有像 GetMessage,用来取得消息;
    而PostThreadMessage是用来发送消息的。
    具体的参数定义、用法参考 Help吧。
    PeekMessage的第一个参数 @Msg ,在Delphi里是 TMsg, 你可以这样定义: var MyMsg : TMsg;
    下面的代码我瞎写的,请大家指正:////////////////// main.pas //////////////
    unit main;interfaceuses
      Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
      StdCtrls,MyThread;
    const
          WM_MyMessage=WM_USER+100;
    type
      TForm1 = class(TForm)
        BtnQuitThread: TButton;
        ListBox1: TListBox;
        BtnPost: TButton;
        BtnStart: TButton;
        BtnExit: TButton;
        procedure BtnQuitThreadClick(Sender: TObject);
        procedure BtnStartClick(Sender: TObject);
        procedure BtnPostClick(Sender: TObject);
        procedure BtnExitClick(Sender: TObject);
      private
        { Private declarations }
      public
        { Public declarations }
          MyThread : MsgThread;
      end;var
      Form1: TForm1;implementation{$R *.DFM}procedure TForm1.BtnQuitThreadClick(Sender: TObject);
    begin
    //  MyThread.Terminate;
      if MyThread = nil then exit;  if PostThreadMessage(MyThread.ThreadID,
          WM_QUIT,0,0) then
          Caption := 'Post Message Ok!'
      else
          Caption := 'Post Message Fail!';
    end;procedure TForm1.BtnStartClick(Sender: TObject);
    begin
      if (MyThread = nil) then
          MyThread := MsgThread.Create(false);
    end;procedure TForm1.BtnPostClick(Sender: TObject);
    begin
      if MyThread = nil then exit;  if PostThreadMessage(MyThread.ThreadID,
          WM_MyMessage,0,0) then
          Caption := 'Post Message Ok!'
      else
          Caption := 'Post Message Fail!';
    end;procedure TForm1.BtnExitClick(Sender: TObject);
    begin
      MyThread.Free;
      Close;
    end;end.
    ///////////// MyThread.pas/////////////////
    unit MyThread;interfaceuses
      Classes,windows, Messages;const
          WM_MyMessage=WM_USER+100;
    type
      MsgThread = class(TThread)
      private
        { Private declarations }
        FMyString : string;
      protected
        procedure Execute; override;
        procedure ShowString;
      end;implementation{ Important: Methods and properties of objects in VCL can only be used in a
      method called using Synchronize, for example,      Synchronize(UpdateCaption);  and UpdateCaption could look like,    procedure PMessage.UpdateCaption;
        begin
          Form1.Caption := 'Updated in a thread';
        end; }{ PMessage }
    uses Main;procedure MsgThread.Execute;
    var Msg : TMsg;
    begin
      { Place thread code here }
      FMyString := 'Thread Start!';
      Synchronize(ShowString);  while  (not Terminated) do
      begin
          if PeekMessage(Msg,0,0,0,PM_REMOVE) then
            begin
                if (Msg.message = WM_QUIT) then
                  begin
                    FMyString := 'Thread Quit';
                    Synchronize(ShowString);
                    Terminate;
                  end;
                if (Msg.message = WM_MyMessage) then
                  begin
                    FMyString := 'Thread Get a USER Message!';
                    Synchronize(ShowString);
                  end;
            end;
      end;
    end;procedure MsgThread.ShowString;
    begin
       Form1.ListBox1.Items.Add(FMyString);
    end;end.
      

  3.   

    thread:
    constructor Create:
      Event := CreateEvent(nil, True, False, nil);
      
    execute
      postMessage(Form1.Handle, WM_MyDefineMsg, 0, 0);
      WaitForSingleObject(Event, INFINITE); //一直等待Form1收到消息
      //或直接用SendMessage
      SendMessage(Form1.Handle, WM_MyDefineMsg, 0, 0);Form1:
    procedure TForm1.MyDefineMsg(var Msg: TMessage);
    begin
      //访问Thread的属性,如string, Integer,如不在同一个Unit,你将这些线程属性public/published,
      SetEvent(Thread.Event); //触发WaitForSingleObject,让它返回,不然那线程会死掉
      msg.Result := 0;//控制消息返回值 = Thread.SendMessage返回值
    end;
      

  4.   

    呵呵 给你SDK的代码1. 子线程中必须要有消息循环队列
    类似这样 不好意思 我写VC的代码了 不过基本上意义都一样DWORD WINAPI ReadThread(LPVOID lpVoid)
    {
    MSG msg;

    while (GetMessage(&msg, NULL, 0, 0))
    {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
    if (msg.message == WM_CAN_READ)
    {
    cout << "read #" << ++g_dwReadTime << " TIMES " << endl;
    int* pArray = (int*)lpVoid;
    for (int i=0; i<20; i++)
    {
    cout << "read in #" << pArray[i] << endl;
    }
    PostThreadMessage(g_dwWrite,
    WM_CAN_WRITE,
    0,
    0);
    }
    }

    return msg.wParam;
    }主线程:
    while (!fPost) // 一定要这样循环发 因为如果只发一次的话 可能会发送失败...
    {
    fPost = PostThreadMessage(g_dwRead,
            WM_CAN_Read,
            0,
            0);
    dwErr = GetLastError();
    szErr[30] = 0;
    if (dwErr != 0)
    {
    wsprintf(szErr, "MainThread Error ID #%d", dwErr);
    cout << szErr << endl;
    }
    else
    {
    fPost = TRUE;
    }
    }
      

  5.   

    // 一定要这样循环发 因为如果只发一次的话 可能会发送失败.......1. 要使用PostThreadMessage
    2. 要循环发 知道发送成功...<每次发消息都需要这样>
    3. 再发消息之后接着就 ShowMessage(IntToStr(GetLastError())); // 一般是1444号错误 
    表示你发送的子线程ID无效 或者 子线程没有消息循环...
      

  6.   

    beyondtkl(大龙驹<暗黑系魔法师&&赏金猎人>)说的“循环发”是正确的,原因是目标线程在一开始建立时,是没有自己的消息队列的,当系统发现它调用GUI相关函数时,才会为该线程建立队列,所以,按微软的建议是用下面类似的代码:
    while not PostThreadMessage(threadID, WM_NULL, 0, 0) do Sleep(100);
    即循环发,直到成功。
      

  7.   

    但,如果,在子线程Execute函数中做检测消息循环,cpu占有率很高,怎么办?
      

  8.   

    >>但,如果,在子线程Execute函数中做检测消息循环,cpu占有率很高,怎么办?
    每個程序都是這樣, 影響不大的, 我想
      

  9.   

    但,客户看cpu占有这么高,会认为你的程序不合理的。
      

  10.   

    如何让子线程检测到消息时才工作,没有消息时,让出CPU时间?
      

  11.   

    >>如何让子线程检测到消息时才工作,没有消息时,让出CPU时间?
    操作系統會處理的, 這個你不用擔心
      

  12.   

    >>操作系統會處理的, 這個你不用擔心
    谢谢你,但我在子线程的EXECUTE 函数中循环检测消息,cpu占有率太高了,因为没有消息时,它还在检测,能有什么办法吗?
      

  13.   

    我写的是在SDK下的处理 还没用过DELPHI的类库...>>操作系統會處理的, 這個你不用擔心
    谢谢你,但我在子线程的EXECUTE 函数中循环检测消息,cpu占有率太高了,因为没有消息时,它还在检测,能有什么办法吗?就是这样的呀... 不过应该不会占有很高的占有率吧....
      

  14.   

    >>但我在子线程的EXECUTE 函数中循环检测消息,cpu占有率太高了
    可以調低線程的優先級>>因为没有消息时,它还在检测,能有什么办法吗?
    所有實現消息循環的程序都是這樣的啊, windows 中有几百上千上萬個類似結構線程在同時運行, 多一個也不算多的
      

  15.   

    给你一个我刚写的例子 基于 console控制台的
    Prj下的program MsgPrj;
    //
    // purpose:  ReadThread VS WriteThread of one integer array with length 20
    // function:
    // 1. Message Queque in sub-thread <for main-thread auto create msg queue by system>
    // 2. thread-communication by PostThreadMessage, so the Read/Write
    //    are synchronous
    // autor: beyondtkl(大龙驹)
    // date:  2004.11.25
    uses
      Windows,
      Messages,
      SysUtils,
      MsgU in 'MsgU.pas';var
      nArray: array[0..19] of Integer;
      hRead, hWrite: THandle;  fPost: LongBool;
      strErr: string;
      dwErr: DWORD;begin
      { TODO -oUser -cConsole Main : Insert code here }
      hWrite := CreateThread(nil,
      0,
      @WriteThread,
      @nArray, // NULL
      0,
      g_dwWrite);
      hRead := CreateThread(nil,
      0,
      @ReadThread,
      @nArray, // NULL
      0,
      g_dwRead);
      fPost := False;
      while not fPost do
      begin
        fPost := PostThreadMessage(g_dwWrite,
      WM_CAN_WRITE,
      0,
      0);
        dwErr := GetLastError();
        if dwErr = 0 then
        begin
          fPost := True;
        end
        else
        begin
          strErr := Format('Error Code Is #%d', [dwErr]);
          WriteLn(strErr);
        end;
      end;
      Sleep(2000); // let read/write 2 seconds
      PostThreadMessage(g_dwWrite,
      WM_QUIT,
      0,
      0);
    PostThreadMessage(g_dwRead,
      WM_QUIT,
      0,
      0);
      CloseHandle(hWrite);
    CloseHandle(hRead);  strErr := Format('write times %d, read times %d', [g_dwWriteTime,g_dwReadTime]);
      WriteLn(strErr);
      ReadLn; // for user view
              // in VC can use syste("pause") prevent the console to be closed
              // but in delphi, i can' got, if someone knows, pls tell me
              // 3x. 
    end.
      

  16.   

    2。 msgU.pas
    // program MsgPrj;
    // autor: beyondtkl(大龙驹)
    // date:  2004.11.25unit MsgU;interfaceuses
      Windows, Messages, SysUtils;const WM_CAN_WRITE = WM_USER + 100;
    const WM_CAN_READ = WM_USER + 101;function WriteThread(lpVoid: Pointer): DWORD; stdcall;
    function ReadThread(lpVoid: Pointer): DWORD; stdcall;var
      g_dwWriteTime: DWORD = 0;
      g_dwReadTime: DWORD = 0;
      g_dwRead: DWORD = 0;
      g_dwWrite: DWORD = 0;implementationfunction WriteThread(lpVoid: Pointer): DWORD;
    var
      msg: TMSG;
      fQuit: Boolean;
      str: string;
      i: Integer;
      pArray: PInteger;
    begin
      fQuit := False;
      while not fQuit do
      begin
        while PeekMessage(msg, 0, 0, 0, PM_REMOVE) do
        begin
          if msg.message = WM_QUIT then
          begin
            fQuit := True;
          end
          else if msg.message = WM_CAN_WRITE then
          begin
            Inc(g_dwWriteTime);
            str := Format('write #%d times', [g_dwWriteTime]);
            WriteLn(str);
            pArray := PInteger(lpVoid);
            for i := 0 to 19 do
            begin
              pArray^ := i;
              Inc(pArray);
              str := Format('write in #%d ', [i]);
              WriteLn(str);
            end;
            PostThreadMessage(g_dwRead,
              WM_CAN_READ,
              0,
              0);
          end
          else
          begin
            TranslateMessage(msg);
            DispatchMessage(msg);
          end;
        end;
      end;
      Result := msg.wParam;
    end;function ReadThread(lpVoid: Pointer): DWORD;
    var
      msg: TMSG;
      pArray: PInteger;
      nValue: Integer;
      str: string;
      i: Integer;
    begin
      while GetMessage(msg, 0, 0, 0) do
      begin
        TranslateMessage(msg);
        DispatchMessage(msg);    if msg.message = WM_CAN_READ then
        begin
          Inc(g_dwReadTime);
          str := Format('write #%d times', [g_dwReadTime]);
          WriteLn(str);
          pArray := PInteger(lpVoid);
          for i := 0 to 19 do
          begin
            nValue := pArray^;
            Inc(pArray);
            str := Format('Read in #%d ', [nValue]);
            WriteLn(str);
          end;
          PostThreadMessage(g_dwWrite,
            WM_CAN_WRITE,
            0,
            0);
        end
      end;  Result := msg.wParam;
    end;end.
      

  17.   

    OK.. 我已经测试 一切OK.
      

  18.   

    ft author 写错了 啊啊啊啊 ^_^
      

  19.   

    TO楼主,你的分线程检测消息队列的代码贴出来看看,我想一定有错误,因为在GetMessage()调用时,如果没有消息,这个线程是处于睡眠状态的(参考API帮助),根本不会占用一点点CPU时间。
      

  20.   

    >>TO楼主,你的分线程检测消息队列的代码贴出来看看,我想一定有错误,因为在GetMessage()调用时,如果没有消息,这个线程是处于睡眠状态的(参考API帮助),根本不会占用一点点CPU时间我使用的是PeekMessage,不是GetMessage,但如果使用Getmessage的话,没有消息时,线程是休眠的,但如果有了消息时,这时线程在休眠状态下,又怎么会收到消息呢?如果再唤醒它的话,岂不还需要监测该子线程是否在休眠下。
      

  21.   

    看看我的代码有说吧用了 PeekMessage && GetMessage...
      

  22.   

    TO楼主:
    PeekMessage()和GetMessage()是有区别的,前者只是瞄一下消息队列,如果有消息就把相关信息放在结构中并返回,如果没有也立刻返回,而后者是必须要等到有消息时才返回。
    用GetMessage(),进入这个API后,如果该线程的消息队列中没有任何消息,则该线程立刻休眠(WINDOWS不再为它分配CPU时间),也就是说,GetMessage()这个API不再返回,直到消息队列中有消息,WINDOWS会知道,这个时候才让GetMessage()返回,唤醒线程。这个唤醒工作是不需要你来做的,而是由WINDOWS来完成,而且,如果你非要唤醒该线程,唯一的办法,就是向这个线程丢一个消息。
    举例如下://线程入口函数
    function MyThread(AParam: Pointer): Integer; stdcall;
    var
      msg: TMsg;
    begin
      ...
      ...
      GetMessage(msg, 0, 0, 0);  //执行到这里时,如果没有消息,
                                 //该API就不会返回,线程也得不到CPU时间
      {直到消息队列中有消息,才会执行下面的代码}
      ...
      ...
      Result := 0;
    end;如果你非要有PeekMessage(),那么在循环里必须加上Sleep(),否则CPU占用率会达到100%,Sleep(0)会起到很好的效果。
      

  23.   

    》》GetMessage()返回,唤醒线程。这个唤醒工作是不需要你来做的,而是由WINDOWS来完成谢谢高手的指点!我明白了。