在DELPHI中虽然TOBJECT是祖先类,但真正开始消息处理和分发的地方并不是直接由它来负责的。TApplication是整分VCL消息系统的初始点。从processmessages方法开始它从windows的消息队列里读取一条消息,这是在一个while循环中完成的。它的代码如下:
  while ProcessMessage(Msg) do可以看到它又读用了另一个方法,这个方法是私有方法。注意processmessage不是processmessages,不要把这两个方法看成是一个。可以看出这个方法一直在不停的调用。而processmessage方法在内部调用一些API来操作消息。(注:Tmsg是一个消息结构,它是真正的对消息结构的封装,而Tmessage消息结构是在vcl内部使用的消息结构,它只是把有用的消息从Tmsg结构提取出来而重新分发的一个消息结构,vcl还提供了更进一步的封装,对于每个重要的消息基本上都提供了相应的专用消息结构,比如说:TWMMouseDown就是一个)首这个方法会把它取出来的消息从系统消息队列中删除,然后再查看如果是wm_quit消息的话就退出执行。如果不是,则去查看Tapplication的OnMessage事件是否为空,如果不是的话则执行些事件。所以一般情况下不要在此事件放入费时的操作,因为此事件实在是太忙了,以至于每秒中有几千条的消息需要经过此事件。然后它再去查看是何种消息。如果没有相应的处理方法。则把消息分发出去。首先得到引消息的方法是窗体过程。这是windows消息系统所要求的。这样由窗体来取得需要这个窗体处理的消息。这是通过句柄来识别的,所以你看句柄真的很消耗系统资源。因为系统需要把这个名柄进行维护和管理。而窗体过程则去给消息分类并调用defwindowproc来取得程序应有的默认行为,然后把分类后的消息转化为vcl内部消息去触发。而最终消息走到最后的终点是defaulthandler在这里你可以做更多的处理。
首先从TMsg结构说起。因为它是直接封装windows消息结构的VCL内部结构类型。它和系统消息结构完全对应。它在windows单元声明。代码如下:
 PMsg = ^TMsg;
  tagMSG = packed record
    hwnd: HWND;
    message: UINT;
    wParam: WPARAM;
    lParam: LPARAM;
    time: DWORD;
    pt: TPoint;
  end;
  {$EXTERNALSYM tagMSG}
  TMsg = tagMSG;
  MSG = tagMSG;
让我们来看看这个结构含义,Hwnd是一个句柄,表示这个消息需要被谁接收处理,实际上Hwnd类型是对应到Longword的一个引强类型声明,这样,编译就会认为Longword和Hwnd不是兼容的类型,而Uint实际也是对应到longword类型。都Lparam和Wparam实际都是longint类型,Dword也是Longword类型。而TPoint是一种结构。大部分的时候它代坐标。vcl把这个类型进行强制类型声明是为了做到和windows系统最大程度上的兼容,同时也照顾了c\c++程序员。因为可以直接使用他们已经习惯了的类型声明。它的成员参数的具体意义如下:message 代表这个消息的IDlParam这个参数据的具体值根据实际的消息类型来决定,比如说它可能是一个代表接键值。
wParam
这个参数的具体意义和用法和lparam差不多。这两个参数就是为了存储消息的附加值的time这个参数表明什么时候把这个消息发送给接收者pt
这代表发送消息的对表的屏幕坐标。
这个结构虽然简单,但却非常的重要,消息就是通过它才得以实现各种功能。
下面讲另一个结构
TMesaage,这个结构只用于VCL对部,并且它兼容于所有特定的消息结构,但不包括Tmsg。而tmsg则真正的兼容所有消息结构。Tmessage结构在messages单元声明,代码如下:
  PMessage = ^TMessage;
  TMessage = packed record
    Msg: Cardinal;
    case Integer of
      0: (
        WParam: Longint;
        LParam: Longint;
        Result: Longint);
      1: (
        WParamLo: Word;
        WParamHi: Word;
        LParamLo: Word;
        LParamHi: Word;
        ResultLo: Word;
        ResultHi: Word);
  end;
可以看出它的是个变体结构,是对tmsg结构最了进一点分化的结果。因此这个结构更易使用。它的主要特点就是Result参数,这个参数主要是为了在响应消息时返回给操作系统一个值,虽然不是所有消息都要求有返回值,但还是有一部分要求,比如说WM_Paint消息就是一个。以下是几个特定的消息结构。
  TWMKey = packed record
    Msg: Cardinal;
    CharCode: Word;
    Unused: Word;
    KeyData: Longint;
    Result: Longint;
  end;  TWMMouse = packed record
    Msg: Cardinal;
    Keys: Longint;
    case Integer of
      0: (
        XPos: Smallint;
        YPos: Smallint);
      1: (
        Pos: TSmallPoint;
        Result: Longint);
  end;  TWMMouseWheel = packed record
    Msg: Cardinal;
    Keys: SmallInt;
    WheelDelta: SmallInt;
    case Integer of
      0: (
        XPos: Smallint;
        YPos: Smallint);
      1: (
        Pos: TSmallPoint;
        Result: Longint);
  end;  TMSHMouseWheel = packed record
    Msg: Cardinal;
    WheelDelta: Integer;
    case Integer of
      0: (
        XPos: Smallint;
        YPos: Smallint);
      1: (
        Pos: TSmallPoint;
        Result: Longint);
  end;
可以看出vcl是如何来封装系统消息的。这样delphi在vcl内部就实现和windows系统消息机制的无逢集成。

解决方案 »

  1.   

    你只是举了几个例子。实际上,还是没有说清楚VCL是如何封装系统消息的。
      

  2.   

    已经有很多人讲解过VCL消息的流向了
      

  3.   

    包括TApplication一般可以处理消息的组件都是从TControl继承的,而wndprc就是在这个类里创建的,在此来处理所有的消息,而最终它去调用了TObject里定义的dispath方法。从而让消息走到了尽头,那么我们可以知道。TApplication得到消息后然后再去调用父类的方法,这一层一层回溯到祖先类的Dispath处理方法中。而在TApplication处理消息时它同时也分发消息。这样每一个拥有wndprc过程的类都可以处理消息,而它们最终调用的也都是Tobject的Dispath,这样就在VCL内部形成了一个消息循环,从而得以让每个类可都有机会得到消息并处理的机会,消息系统就这样被构建出来了。
      

  4.   

    包括TApplication一般可以处理消息的组件都是从TControl继承的,而wndprc就是在这个类里创建的,在此来处理所有的消息,而最终它去调用了TObject里定义的dispath方法。从而让消息走到了尽头,那么我们可以知道。TApplication得到消息后然后再去调用父类的方法,这一层一层回溯到祖先类的Dispath处理方法中。而在TApplication处理消息时它同时也分发消息。这样每一个拥有wndprc过程的类都可以处理消息,而它们最终调用的也都是Tobject的Dispath,这样就在VCL内部形成了一个消息循环,从而得以让每个类可都有机会得到消息并处理的机会,消息系统就这样被构建出来了。
      

  5.   

    那么 activeX控件是如何处理消息的呢?
      

  6.   

    你只是看了一些 VCL 库的代码,
    有一点了解。
      

  7.   

    不过他说的内容跟VCL几乎沾不上边。那些都是Win32 SDK 的基础知识