DECLARE_MESSAGE_MAP()与消息传递网

一.总体结构

首先,在.h文件中:

DECLARE_MESSAGE_MAP()

然后在.CPP文件中:

BEGIN_MESSAGE_MAP(CView, CWnd)

          ON_COMMAND(CViewid,0)

END_MESSAGE_MAP()

上面.h中的宏的声明是:

#define DECLARE_MESSAGE_MAP\

static AFX_MSGMAP_ENTRY _messageEntries[];\

static AFX_MSGMAP messageMap;\

virtual AFX_MSGMAP*GetMessageMap()const;

该宏相当于在类中声明两个static数据成员和一个虚成员函数。 

它们的定义由.CPP中的三个宏实现:

#define BEGIN_MESSAGE_MAP(class_name,base_class)\

AFX_MSGMAP*class_name::GetMessageMap()const\

       {return &class_name::message;}\

AFX_MSGMAP messageMap=\

      {&base_class::messageMap,class_name::_messageEntries}\

AFX_MSGMAP_ENTRY _messageEntries[]=\

      {

#define ON_COMMAND(id,memFunc)\

              {WM_COMMAND,0,id,id,AFx_sig_vv,(AFX_PMSG)memFunc },

#define END_MESSAGE_MAP()\

     {0,0,0,0,AfxSig_end,(AFX_PMSG)0}\

      };

注意这三个宏中的内容共同完成了一个AFX_MSGMAP_ENTRY结构体数组的填写,其花括号上面用红色斜体标了出来。因此这三个宏必须连在一起调用,且前后顺序必须正确

总体来说,就是DECLARE_MESSAGE_MAP负责俩个成员变量与一个成员函数的声明,BEGIN_MESSAGE_MAPON_COMMANDEND_MESSAGE_MAP负责声明所对应的实现。

二.关于声明

至于其中声明的成员变量,如下:

1.  AFX_MSGMAP。该结构体负责存储两个指针,分别指向基类的 AFX_MSGMAP,以及本类的消息映射表AFX_MSGMAP_ENTRY

struct AFX_MSGMAP

{

AFX_MSGMAP *pBaseMessageMap;//指向基类的本结构。

AFX_MSGMAP_ENTRY*lpEntries;//本类的消息映射表。

};

2.消息映射表AFX_MSGMAP_ENTRY。该结构体可以存储一条消息的所有相关信息。在类中,使用了该结构体类型的数组,因此本类有多少消息,就需要在数组中存多少元素。

struct AFX_MSGMAP_ENTRY

{

UINT nMessage;

UINT nCode;

UINT nID;

UINT nLastID;

UINT nSig;

AFX_PMSG pfn;

};

该结构体最后的成员AFX_PMSG也是个结构体,其声明如下:

3.函数指针

typedef void (CCmdTarget::*AFX_PMSG)(void);  

很明显,AFX_PMSG指向的函数指针是相应消息的处理函数。当触发某个消息时,就会调用该消息所对应的函数指针。

以上声明,展开就是:

ClassCView:public CWnd

{

Public:

       ……

static AFX_MSGMAP_ENTRY  _messageEntries[];\

static AFX_MSGMAP  messageMap;\

virtual AFX_MSGMAP*GetMessageMap()const;

};

三.关于实现

.CPP中的三个宏,负责对.h声明的两个成员变量与一个成员函数进行实现。展开后:

AFX_MSGMAP*class_name::GetMessageMap()const

     {

return &class_name::message;

}

AFX_MSGMAP messageMap=

{     &base_class::messageMap,class_name::_messageEntries

}

AFX_MSGMAP_ENTRY _messageEntries[]=

{    

       {WM_COMMAND,0,id,id,AFx_sig_vv,(AFX_PMSG)memFunc },

{0,0,0,0,AfxSig_end,(AFX_PMSG)0}

     };

可见,本类中主要的数据成员只有一个,就是消息映射表AFX_MSGMAP_ENTRY数组。

AFX_MSGMAP的两个成员变量,一个指向基类AFX_MSGMAP_ENTRY,一个指向本类的AFX_MSGMAP_ENTRY

而那个成员函数GetMessageMap()则是用来获取本类的AFX_MSGMAP的。

  

因此,若有派生关系:CCmdeTarget->CWnd->CView->CMyView

则:

可以通过GetMessageMap()用来获取CMyViewAFX_MSGMAP,从而得到CMyViewAFX_MSGMAP_ENTRY和基类的AFX_MSGMAP (也就是CViewAFX_MSGMAP) 。

由于得到了CViewAFX_MSGMAP,于是又有了CViewAFX_MSGMAP_ENTRY和基类的AFX_MSGMAP (也就是CWndAFX_MSGMAP) 。

同理,可以获取CCmdeTargetAFX_MSGMAP。但CCmdeTarget就是最终消息的源头类了,不会再上溯。因此CCmdeTargetAFX_MSGMAP需要单独实现。

故而,一条消息,交给一个派生类对象CMyView后,可以不断上溯,直到到达CCmdeTarget

这,就是消息传递网。这张网为消息在基类与派生类之间传递提供了通道。但现在仅仅是架设了一张网,消息进来后,还是不能自行传递或流动,缺乏一个推动消息前进的动力。该动力属于Windows程序设计的工作。

特别注意,在这张网中,消息一定是由派生类流向基类的,纵向流动,而不能逆流(基类流向派生类)或者横流(流向兄弟类)对于一般的Windows消息(WM_xxx),一定遵循此规则。

对于命令消息WM_COMMAND,消息流动则可能有其他路线。

 

夹在BEGIN_MESSAGE_MAP与END_MESSAGE_MAP之间的宏,上面是ON_COMMAND。该宏的作用是将消息与消息处理函数绑定。但除了ON_COMMAND之外,还有很多其他的宏也用于这里。比如ON_ WM_CREATEON_WM_LBUTTONDOWNON_WM_PAINT等。

不同之处在于,ON_COMMAND宏可以将很多不同类型的消息与处理函数绑定,而不局限于某个固定的消息。但如ON_WM_CREATE宏,则只用于将WM_CREATE消息与消息处理函数OnCreate绑定。

所以,对于每个非WM_COMMAND的Windows标准消息,也就是WM_xxx,都有一个已经定义好的宏ON_ WM_xxx负责该消息跟处理函数的绑定。

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值