Windows消息机制的应用【Delphi版】

两类主要消息处理函数:

1)向自身分发消息,由自己的成员函数处理:Dispatch(var message:string);  同步

2)向指定的类投递消息: a)SendMessage    异步投递

                                   b)PostMessage     同步投递

 

一.自定义消息号和消息结构

const
  WM_5001=WM_USER+5001;
  WM_5002=WM_USER+5002;
  WM_5003=WM_USER+5003;
  WM_6001=WM_USER+6001;

type

  //自定义消息结构
  PMsgRec = ^TMsgRec;
  TMsgRec = record
    msgNo   : Cardinal;
    msgText: string;
  end;

 

二.消息分发

    向特定的对象分发消息:Dispatch函数

    原理:

         在TObject类中,有一个Dispatch()方法和一个DefaultHandler()方法,它们都是与消息
    分发机制相关的。
    Dispatch()负责将特定的消息分发给合适的消息处理函数。首先它会在对象本身类型
    的类中寻找该消息的处理函数,如果找到,则调用它;如果没有找到而该类覆盖了TObject
    的DefaultHandler(),则调用该类的DefaultHandler();如果两者都不存在,则继续在其基
    类中寻找,直至寻找到TObject这一层,而TObject已经提供了默认的DefaultHandler()
    方法。  

    消息接收类:TMsgAccepter

//自定义消息接收类
  TMsgAccepter=class
  private
    procedure Msg5001Accepter(var msg:TMsgRec); message WM_5001;

  public
    procedure defaultHandler(var message); override;

  end;

implementation
uses
  Main;

{ TMsgAccepter }
procedure TMsgAccepter.Msg5001Accepter(var msg: TMsgRec);
begin
    FrmMain.Memo1.Lines.Add('接收类已收到5001消息,并对其进行了处理!')
end;

procedure TMsgAccepter.defaultHandler(var message);
var
  theMsg:TMsgRec;
begin
  theMsg:=TMsgRec(message);
  FrmMain.Memo1.Lines.Add('接收类收到消息请求,但该消息号无指定处理函数!消息号为:'+IntToStr(theMsg.msgNo));
end;

    a)向对象theMsgAccepter分发消息WM_5001(有对应处理函数

var
  theMsg:TMsgRec;
begin
  theMsg.msgNo:=WM_5001;
  theMsg.msgText:='';
  theMsgAccepter.Dispatch(theMsg);
end;

      运行结果:

     

    b)向对象theMsgAccepter分发消息WM_6001(无对应处理函数

var
  theMsg:TMsgRec;
begin
  theMsg.msgNo:=WM_6001;
  theMsg.msgText:='';
  theMsgAccepter.Dispatch(theMsg);
end;

      运行结果:

      

 

三.消息投递:向特定窗口投递消息

     消息响应窗口:TFrmMsgProcess

  TFrmMsgProcess = class(TForm)
    Memo1: TMemo;
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
    procedure Msg5002Accepter(var msg:TMessage); message WM_5002;
    procedure Msg5003Accepter(var msg:TMessage); message WM_5003;
  public
    { Public declarations }
  end;

var
  FrmMsgProcess: TFrmMsgProcess;

implementation
uses
  Main;

{$R *.dfm}

{ TFrmMsgProcess }

procedure TFrmMsgProcess.Msg5002Accepter(var msg:TMessage);
var
  pTheMsg:PMsgRec;
begin
   Self.Memo1.Lines.Add('窗口已收到5002号消息,并开始进行处理。。。');

   Self.Memo1.Lines.Add('窗口收到的字符串参数信息为:'+String(msg.WParam));
   pTheMsg:=PMsgRec(msg.LParam);
   Self.Memo1.Lines.Add('窗口收到的结构体参数信息为:'+pTheMsg.msgText);
   
   Self.Memo1.Lines.Add('窗口对5002号消息的处理已完成!');
end;

procedure TFrmMsgProcess.FormCreate(Sender: TObject);
begin
   self.Memo1.Color:=clblack;
   self.Memo1.Font.Color:=clgreen;
end;

procedure TFrmMsgProcess.Msg5003Accepter(var msg: TMessage);
begin
   FrmMain.Memo1.Lines.Add('窗口已收到5003号消息,并开始进行处理。。。');
   Sleep(1000);
   FrmMain.Memo1.Lines.Add('窗口对5003号消息的处理已完成!');
end;

      a)异步方式:Postmessage,发出后不等待,直接返回

begin
  Self.Memo1.Lines.Add('主线程向子窗口发送5003号消息。。。');

  PostMessage(FrmMsgProcess.Handle,WM_5003,0,0);

  Self.Memo1.Lines.Add('主线程消息发送函数已结束!');
end;

        运行结果:

      

     b)同步方式:SendMessage,等窗口响应后,再返回

begin
  Self.Memo1.Lines.Add('主线程向子窗口发送5003号消息。。。');

  SendMessage(FrmMsgProcess.Handle,WM_5003,0,0);

  Self.Memo1.Lines.Add('主线程消息发送函数已结束!');
end;

       运行结果: 

      

     c)带参数信息的消息投递

             发送“字符串或结构体”时,尽可能用sendMessage,否则,可能内存中的内容

        已被更改,而窗口消息响应函数还未处理。

var
  msgStr:string;
  theMsg:TMsgRec;
begin
  msgStr:='WM_5002消息的字符串说明';
  theMsg.msgNo:=WM_5002;
  theMsg.msgText:='WM_5002消息的结构体说明';
  SendMessage(FrmMsgProcess.Handle,WM_5002,WParam(PChar(msgStr)),LParam(@theMsg));
end;

         运行结果:

        

   PS:以上均是在同一个进程里投递消息,若在不同进程间投递消息,则必须使用“内存映射文件”存储字符

    串或结构体消息,而不是直接放在消息参数sparam和lparan中,那样会出现地址空间访问冲突的问题。

四.其他

      a)wparam与lparam

         wParam: 原win16系统中,word类型的整数,16位;现在的win32系统中,扩展为32位整型。
         lParam:   原win16系统中,long类型的整数,32位;现在的win32系统中,32位整型。

         注:WPARAM常常代表一些控件的ID或者高位底位组合起来分别表示鼠标的位置,如果

           消息的发送者需要将某种结构的指针或者是某种类型的句柄时,习惯上用LPARAM来传递。

      b)常用消息处理函数

    Peekmessage()   从消息队列中读消息
        Getmessage()   可以有选择的从消息列表中得到消息,一般用在window的窗口过程函数里面
        DispatchMessage()   用来派送消息到窗口过程
        TranslateMessage()   用于将Virtul-Key消息翻译为字符消息
        Postthreadmessage()   用于向线程发送消息
        Postmessage()   用于将消息传送到窗口的消息队列
        SendMessage()不经过消息队列而直接发送给窗口的

      c)窗口过程函数

            从消息队列中取消息
            重写窗口默认“窗口过程函数”

      d)消息路由

           

      e)参考界面 线程安全  

              http://blog.csdn.net/danscort2000/article/details/2780418   ——原理
              http://topic.csdn.net/t/20040908/15/3352501.html   ——消息机制的使用

posted @ 2012-05-14 17:07  edisonfeng  阅读(2752)  评论(0编辑  收藏  举报