Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1466678
  • 博文数量: 218
  • 博客积分: 6394
  • 博客等级: 准将
  • 技术积分: 2563
  • 用 户 组: 普通用户
  • 注册时间: 2008-02-08 15:33
个人简介

持之以恒

文章分类

全部博文(218)

文章存档

2013年(8)

2012年(2)

2011年(21)

2010年(55)

2009年(116)

2008年(16)

分类: WINDOWS

2009-07-25 14:30:07

消息映射和命令传递

l  消息的分类:

    MFC将消息分成三类:

l  命令消息(WM_COMMAND)

UI对象产生的消息都是这种命令消息,可能来自于菜单、加速键、或者是工具栏按钮。凡是派生自CCmdTarget的类都有资格接收命令消息

l  标准消息

除了WM_COMMAND之外,任何以WM_开头的都算是这一类。任何派生自CWnd的类都可以接收此消息

l  Control Notification

这种消息由控件产生,为了是向其父窗口通知某种情况

三个宏定义

                   DECLARE_MESSAGE_MAP()表示该类拥有相应的消息映射表格

                   BEGIN_MESSAGE_MAP(CLASSNAME,FACLASSNAME)

                      ONCOMMAND()//指定消息处理函数的名称

                   END_MESSAGE_MAP

以上的几个宏对应一个庞大的数据结构

DECLARE_MESSAGE_MAP()对应的是

#define DECLARE_MESSAGE_MAP() \

 static AFX_MESSAGE_ENTRY _messageEntries[]; \

 static AFX_MSGMAP messageMap;\

           virtual AFX_MSGMAP * GetMessageMap() const;

struct AFX_MSGMAP

 {

            AFX_MAGMAP * pBaseMessageMap;

             AFX_MSGMAP_ENTRY * lpEnteries;

}

其中AFX_MSGMAP_ENTRY的定义如下:

struct AFX_MSGMAP_ENTRY //MFC 4.0 format

{

 UINT nMessage; //windows message

 UINT nCode;    //control code or WM_NOTIFY code

 UINT nID;    //control ID(or o for windows message)

 UINT nLastID;    //used for entries specifying a range og control id’s

UINT nSig;    //signature type (action) or pointer to message

 AFX_PMSG pfn;    /runtime to call ( or special value)

}

也就是如下图所示的数据结构


下面就是使用BEGIN.../ON.../END...宏来进行填充相应的数据结构

       DECLARE_MESSAGE_MAP的内容填充工作由三个宏完成:

#define BEGIN_MESSAGE_MAP(theClass,baseClass) \

 AFX_MSGMAP * theClass::GetMessageMap() const \

           { return &theClass::messageMap; } \

           AFX_MSGMAP theClass::messageMap = \

            (&(baseClass::messageMap),\

(AFX_MSGMAP_ENTRY *)&(theClass::_messageEntries));\

       AFX_MSGMAP_ENTRY theClass::messageEntries[] = \

{

              #define ON_COMMAND (id,memberFxn) \

        (WM_COMMAND,0,(WORD)id,(WORD)id,AfxSig_vv,(AFX_PMSG)memberFxn),                     #define END_MESSAGE_MAP( )\

        (0,0,0,0,AfxSig_end, (AFX_PMSG)0 ) \

};

其中的AfxSig_end定义为:

enum AfxSig

{

             AfxSig_end = 0, //{marks end of message map}

             AfxSig_vv,

};

       AfxSig_XX用来描述消息处理程序memberFxn的类型(参数和返回值)

消息的传递:

AfxWndProc开始

首先来看CWND::WindowProcè调用OnWndMsg(message,wParam,lParam,&lResult),他是用来分配和处理消息的专职的机构

命令消息由OnCommand进行处理

通知消息由OnNotify进行处理

一般的Windows消息,直接在消息的映射表进行上溯,寻找其对应的消息处理程序

BOOL CWnd::OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult)

{

如果是WM_COMMAND消息,由虚拟函数OnCommand处理,
 //WM_COMMAND
由菜单、工具条等发出,表示特定的命令,与窗口消息由所不同。
 if (message == WM_COMMAND)
 {
  ....
  OnCommand(wParam, lParam))
  ....
 }
 //
如果消息是WM_NOTIFY,即通知消息,由虚拟函数OnNotify处理,
 if (message == WM_NOTIFY)
 {
  .....
  OnNotify(wParam, lParam, &lResult))
  .....
 }
 
 //
对特殊消息的处理:
 WM_ACTIVATE...
 WM_SETCURSOR...
 //
普通消息
 .......
 //
在类消息映射中查找消息对应的消息处理函数。
 //
参数转换等等...
 .......
 //
找到后,调用该函数。
 mmf.pfn = lpEntry->pfn;
 lResult = (this->*mmf.pfn_lwl)(wParam, lParam);

 .......
}

OnCommand

调用时机:

OnWndMsg中,如果消息是WM_COMMAND,即命令消息,将调用OnCommand;

OnCommand中可以对命令处理进行操作。

CWnd实现:

BOOL CWnd::OnCommand(WPARAM wParam, LPARAM lParam)
{
  .....
  //
试探性的调用OnCmdMsg(,,CN_UPDATE_COMMAND_UI..)看当前命令项是否有效
  CTestCmdUI state;
  state.m_nID = nID;
  OnCmdMsg(nID, CN_UPDATE_COMMAND_UI, &state, NULL);
  if(...)//
命令有效时设置标志为命令标志:CN_COMMAND
  nCode = CN_COMMAND;

  ....

}

命令消息的接收物类型

处理次序

Frame窗口

View

Frame本身

CWinAPP对象

View

View本身

Document

Document

Document本身

Document Template

                            WM_COMMAND的特殊的处理次序


阅读(1316) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~