MFC教程(4)
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
MFC 教程( 4)
可是在目前例子中,目前对象的类CTview 没有覆盖该函数,所以CWnd 的 WindowProc被调用。
这个函数把下一步的工作交给OnWndMsg函数来办理。
如
果 OnWndMsg 没有办理,则交给 DefWindowProc 来办理。
OnWndMsg和DefWindowProc都是CWnd类的虚构函数。
OnWndMsg的原型以下:
BOOL CWnd::OnWndMsg( UINT message,
WPARAM wParam, LPARAM lParam,RESULT*pResult );
该函数是虚构函数。
和 WindowProc 相同,因为目前对象的类 CTview 没有覆盖该函数,所以 CWnd 的 OnWndMsg 被调用。
在 CWnd 中,MFC 使用 OnWndMsg 来分别办理各种信息:假
如是 WM_COMMAND 信息,交给 OnCommand 办理;而后返回。
假如是 WM_NOTIFY 信息,交给 OnNotify 办理;而后返回。
假如是 WM_ACTIVATE 信息,先交给 _AfxHandleActivate
办理(后边5.3.3.7 节会解说它的办理),再持续下边的办理。
假如是 WM_SETCURSOR 信息,先交给
_AfxHandleSetCursor 办理;而后返回。
假如是其余的Windows信息(包含WM_ACTIVATE),则
第一在信息缓冲池进行信息般配,
若般配成功,则调用相应的信息办理函数;
若不可功,则在信息目标的信息映照数组中进行查找般配,
看它能否办理目前信息。
这里,信息目标即CTview 对象。
假如信息目标办理了该信息,则会般配到信息办理函数,调
用它进行办理;
不然,该信息没有被应用程序办理,OnWndMsg返回FALSE。
对于 Windows信息和信息办理函数的般配,见下一节。
缺省办理函数DefWindowProc将在议论对话框等的实现时
详细剖析。
Windows信息的查找和般配
CWnd 或许派生类的对象调用OnWndMsg搜寻本对象或许
基类的信息映照数组,找寻目前信息的信息办理函数。
假如
目前对象或许基类办理了目前信息,则必然在此中一个类的
信息映照数组中般配到目前信息的办理函数。
信息般配是一个比较耗时的任务,为了提升效率, MFC 设计
了一个信息缓冲池,把要办理的信息和般配到的信息映照条
目(条目包含了信息办理函数的地点)以及进行信息办理的
目前类等信息组成一条缓冲信息,放到缓冲池中。
假如此后
又有相同的信息需要同一个类办理,则直接从缓冲池查找到
对应的信息映照条目就能够了。
MFC 用哈希查找来查问信息映照缓冲池。
信息缓冲池相当于一个哈希表,它是应用程序的一个全局变量,能够放512 条最新用到的信息映照条目的缓冲信息,每一条缓冲信息是哈
希表的一个进口。
采纳 AFX_MSG_CACHE结构描绘每条缓冲信息,其定义如下:
struct AFX_MSG_CACHE
{
UINT nMsg;
const AFX_MSGMAP_ENTRY* lpEntry;
const AFX_MSGMAP* pMessageMap;
};
nMsg 寄存信息 ID ,每个哈希表进口有不同的 nMsg 。
lpEnty 寄存和信息 ID 般配的信息映照条目的地点,它可能
是 this 所指对象的类的映照条目,也可能是这个类的某个基
类的映照条目,也可能是空。
pMessageMap寄存信息办理函数般配成功时进行信息办理
的目前类( this 所指对象的类)的静态成员变量messageMap 的地点,它独一的表记了一个类(每个类的messageMap
变量都不相同)。
this 所指对象是一个CWnd 或其派生类的实例,是正在办理
信息的 MFC 窗口对象。
哈希查找:使用信息ID 的值作为重点值进行哈希查找,如
果成功,即可从lpEntry 获取信息映照条目的地点,从而得
到信息办理函数及其原型。
怎样判断能否成功般配呢?有两条标准:
第一,目前要办理的信息message在哈希表(缓冲池)中
有进口;第二,目前窗口对象(this 所指对象)的类的静态
变量 messageMap的地点应当等于本条缓冲信息的pMessagMap 。
MFC 经过虚构函数GetMessagMap获取messageMap的地点。
假如在信息缓冲池中没有找到般配,则搜寻目前对象的信息
映照数组,看能否有适合的信息办理函数。
假如般配到一个信息办理函数,则把般配结果加入到信息缓
冲池中,即填写该条信息对应的哈希表进口:
nMsg=message;
pMessageMap=this->GetMessageMap;
lpEntry= 查找结果
而后,调用般配到的信息办理函数。
不然(没有找到),使
用_GetBaseMessageMap 获取基类的信息映照数组,查找
和般配;直到般配成功或找寻了全部的基类(到 CCmdTarget )为止。
假如最后没有找到,则也把该条信息的般配结果加入到缓冲
池中。
和般配成功不同的是:指定lpEntry 为空。
这样OnWndMsg 返回,把控制权返还给 AfxCallWndProc 函数,AfxCallWndProc 将持续调用 DefWndProc 进行缺省办理。
信息映照数组的搜寻在 CCmdTarget::OnCmdMsg 函数中也用到了,并且算法相同。
为了提升速度, MFC 把和信息映照数组条目逐个比较、般配的函数 AfxFindMessageEntry 用汇编书写。
const AFX_MSGMAP_ENTRY* AFXAPI AfxFindMessageEntry(const
AFX_MSGMAP_ENTRY* lpEntry,
UINT nMsg, UINT nCode, UINT nID)
第一个参数是要搜寻的映照数组的进口;第二个参数是Windows信息表记;第三个参数是控制通知信息表记;第四个参数是命令信息表记。
对 Windows信息来说,nMsg是每条信息不同的,nID 和nCode 为 0。
对命令信息来说, nMsg 固定为 WM_COMMAND ,nID 是每条信息不同, nCode 都是 CN_COMMAND (定义为 0)。
对控制通知信息来说, nMsg 固定为 WM_COMMAND 或许
WM_NOTIFY ,nID 和 nCode 是每条信息不同。
对于 Register 信息, nMsg 指定为 0XC000 , nID 和 nCode 为0。
在使用函数 AfxFindMessageEntry 获取般配结果以后,
还一定判断 nSig 能否等于 message ,只有相等才调用对应的
信息办理函数。
Windows信息办理函数的调用
对一个 Windows信息,般配到了一个信息映照条目以后,
将调用映照条目所指示的信息办理函数。
调用办理函数的过程就是变换映照条目的pfn指针为适合的函数种类并履行它:MFC定义了一个成员函数指针mmf,第一把信息办理函数的地点赋值给该函数指针,而后依据消
息映照条目的nSig 值变换指针的种类。
可是,要给函数指
针 mmf 赋值,一定使该指针能够指向全部的信息办理函数,
为此则该指针的种类是全部种类的信息办理函数指针的结合
体。
对上述过程, MFC 的实现大概以下:
union MessageMapFunctions mmf;
mmf.pfn = lpEntry->pfn;
swithc (value_of_nsig){
case AfxSig_is: //OnCreate 就是该种类 lResult
= (this->*mmf.pfn_is)((LPTSTR)lParam); break;
default:
ASSERT(FALSE); break;
}
LDispatchRegistered: //办理registered windows messages
ASSERT(message >= 0xC000);
mmf.pfn = lpEntry->pfn;
lResult = (this->*mmf.pfn_lwl)(wParam, lParam);
假如信息办理函数有返回值,则返回该结果,不然,返回
TRUE 。
对于图 4-1 所示的例子, nSig 等于 AfxSig_is ,所以将履行
语句
(this->*mmf.pfn_is)((LPTSTR)lParam)
也就是对 CTview::OnCreate的调用。
趁便指出,对于 Registered窗口信息,信息办理函数都是同一原型,所以都被变换成lwl 型(对于 Registered窗口信息的映照,见 4.4.2 节)。
综上所述,标准Windwos 信息和应用程序信息中的
Registered信息,由窗口过程直接调用相应的办理函数办理:
假如某个种类的窗口(C++ 类)办理了某条信息(覆盖了
CWnd 或直接基类的办理函数),则对应的HWND 窗口
(W inodws window )收到该信息时就调用该覆盖函数来办理;假如该类窗口没有办理该信息,则调用实现该办理函数最直接
的基类(在 C++ 的类层次上靠近该类)来办理,上述例子中假
如 CTview 不办理 WM_CREATE 信息,则调用上一层的CWnd::OnCreate 办理;
假如基类都不办理该信息,则调用 DefWndProc 来办理。
信息
映照体制达成虚构函数功能的原理
综合对 Windows 信息的办理来看, MFC 使用信息映照体制达
成了 C++ 虚构函数的功能。
这主要鉴于以下几点:
全部办理信息的类从 CCmdTarget 派生。
使用静态成员变量 _messageEntries 数组寄存信息映照条目,使
用静态成员变量messageMap 来独一地域别和获取类的信息映照。
经过 GetMessage 虚构函数来获取目前对象的类的
messageMap变量,从而获取信息映照进口。
依据先基层,后基层的次序在类的信息映照数组中搜寻信息
办理函数。
鉴于这样的体制,一般在覆盖基类的信息办理函
数时,应当调用基类的同名函数。
以上论断适合于MFC 其余信息办理体制,如对命令信息的
办理等。
不同的是其余信息办理有一个命令派发/散发的过程。
下一节,议论命令信息的接受和办理。
对命令信息的接收和办理
MFC 标准命令信息的发送
在 SDI 或许 MDI 应用程序中,命令信息由用户界面对象(如菜单、工具条等)产生,而后送给主边框窗口。
主边框窗口
使用标准 MFC 窗口过程办理命令信息。
窗口过程把命令传
递给 MFC 主边框窗口对象,开始命令信息的散发。
MFC 边
框窗口类 CFrameWnd供给了信息散发的能力。
下边,仍是经过一个例子来说明命令信息的办理过程。
使用 AppWizard 产生一个单文档应用程序 t。
从 help 菜单项选择
择“ About ”,就会弹出一个ABOUT 对话框。
下边,议论从命
令信息的发出到对话框弹出的过程。
第一,选择“ About ”菜单项的动作致使一个Windows命令消
息 ID_APP_ABOUT 的产生。
Windows 系统发送该命令信息
到边框窗口,致使它的窗口过程AfxWndProc被调用,参数
1 是边框窗口的句柄,参数
2 是信息 ID(即 WM_COMMAND),
参数 3、4 是信息参数,参数 3 的值是 ID_APP_ABOUT 。
接着
的系列调用如图 4-3 所示。
下边分别叙述每一层所调用的函数。
前 4 步同对 Windows 信息的办理。
这里接受信息的HWND
窗口是主边框窗口,所以,AfxWndProc依据HWND句柄得到的 MFC 窗口对象是MFC 边框窗口对象。
在 4.2.2 节谈到,假如 CWnd::OnWndMsg 判断要办理的信息是命令信息 (WM_COMMAND) ,就调用 OnCommand 进
一步办理。
因为 OnCommand 是虚构函数,目前 MFC 窗口对象是边框窗口对象,它的类从 CFrameWnd 类导出,没有覆盖CWnd 的虚构函数 OnCommand ,而 CFrameWnd 覆
盖了 CWnd 的 OnCommand ,所以, CFrameWnd 的OnCommand 被调用。
换句话说, CFrameWnd 的OnCommand 被调用是动向拘束的结果。
接着介绍的本例子的
有关调用,也是经过动向拘束而实质发生的函数调用。
接着的有关调用,将不进行为何调用某个类的虚构或许消
息办理函数的剖析。
(1) CFrameWnd 的 OnCommand 函数
BOOL CFrameWnd::OnCommand(WPARAM wParam, LPARAM lParam)
参数 wParam 的低阶 word 寄存了菜单命令nID 或控制子窗口 ID ;假如信息来自控制窗口,高阶word寄存了控制通知信息;假如信息来自加快键,高阶word值为1;假如信息来自菜单,高阶word值为0。
假如是通知信息,参数lParam 寄存了控制窗口的句柄hWndCtrl ,其余状况下lParam 是 0。
在这个例子里,低阶word 是 ID_APP_ABOUT,高阶word 是 1; lParam 是 0。
MFC 对 CFrameWnd 的缺省实现主假如获取一个时机来检查程
序能否运转在HELP 状态,需要履行上下文帮助,假如不需要,则调用基类的 CWnd::OnCommand 实现正常的命令信息发送。
(2) CWnd 的 OnCommand 函数
BOOL CWnd::OnCommand(WPARAM wParam, LPARAM lParam)
它按必定的次序办理命令或许通知信息,假如发送成功,返
回 TRUE ,不然, FALSE 。
办理次序以下:
假如是命令信息,则调用 OnCmdMsg(nID,
CN_UPDATE_COMMAND_UI, &state, NULL)测试nID命令能否已经被严禁,假如这样,返回FALSE ;不然,调用OnCmdMsg进行命令发送。
对于
CN_UPDATE_COMMAND_UI 通知信息,见后边用户界面状
态的更新办理。
假如是控制通知信息,则先用 ReflectLastMsg 反射通知信息到
子窗口。
假如子窗口办理了该信息,则返回 TRUE ;不然,调
用 OnCmdMsg 进行命令发送。
对于通知信息的反射见后
面 4.4.4.3 节。
OnCommand 给 OnCmdMsg 传达四个参数:nID ,即命令信息ID ;nCode ,假如是通知信息则为通知代码,假如是命令信息则为NC_COMMAND(即0);其余两个参数为空。
(3) CFrameWnd 的 OnCmdMsg 函数
BOOL CFrameWnd::OnCmdMsg(UINT nID, int nCode,
void* pExtra,
AFX_CMDHANDLERINFO* pHandlerInfo)
参数 1 是命令 ID ;假如是通知信息( WM_COMMAND 或许WM_NOTIFY ),则参数 2 表示通知代码,假如是命令信息,参数 2 是 0;假如是 WM_NOTIFY ,参数 3 包含了一些额外的信息;参数 4 在正常信息办理中应当是空。
在这个例子里,参数 1 是命令 ID ,参数 2 为 0,参数 3 空。
OnCmdMsg 是虚构函数, CFrameWnd 覆盖了该函数,目前对象( this 所指)是 MFC 单文档的边框窗口对象。
故CFrameWnd 的 OnCmdMsg 被调用。
CFrameWnd::OnCmdMsg 在 MFC 信息发送中据有特别重要的地位, MFC 对该函数的缺省实现确立了 MFC 的标准命
令发送路径:
送给活动( Active )视办理,调用活动视的 OnCmdMsg 。
因为目前对象是 MFC 视对象,所以, OnCmdMsg 将搜寻 CTview 及其基类的信息映照数组,试图获取相应的办理函
数。
假如视对象自己不办理,则视获取和它关系的文档,调用关
联文档的 OnCmdMsg 。
因为目前对象是MFC 视对象,所以,OnCmdMsg将搜寻CTdoc及其基类的信息映照数组,试图
获取相应的办理函数。
假如文档对象不办理,则它获取管理文档的文档模板对象,
调用文档模板的OnCmdMsg 。
因为目前对象是MFC 文档模板对象,所以,OnCmdMsg将搜寻文档模板类及其基类的
信息映照数组,试图获取相应的办理函数。
假如文档模板不办理,则把没有办理的信息逐级返回:文档
模板告诉文档对象,文档对象告诉视对象,视对象告诉边框
窗口对象。
最后,边框窗口得悉,视、文档、文档模板都没
有办理信息。
CFrameWnd的OnCmdMsg持续调用CWnd::OnCmdMsg (斜体表示有类属限制)来办理信息。
因为 CWnd 没有覆盖OnCmdMsg ,故实质上浮用了函数
CCmdTarget::OnCmdMsg 。
因为目前对象是MFC 边框窗口对象,所以 OnCmdMsg函数将搜寻CMainFrame类及其所有基类的信息映照数组,试图获取相应的办理函数。
CWnd 没有实现OnCmdMsg 却指定要履行其OnCmdMsg 函数,可能是为了此后 MFC 给 CWnd 实现了 OnCmdMsg 以后其余代码不用改变。
这一步是边框窗口自己试试办理信息。
假如边框窗口对象不办理,则送给应用程序对象办理。
调用CTApp 的 OnCmdMsg ,因为实质上CTApp 及其基类CWinApp没有覆盖OnCmdMsg ,故实质上浮用了函数CCmdTarget::OnCmdMsg 。
因为目前对象是MFC 应用程序对象,所以 OnCmdMsg函数将搜寻CTApp 类及其全部基类的的信息映照进口数组,试图获取相应的办理函数
假如应用程序对象不办理,则返回 FALSE ,表示没有命令目标办理目前的命令信息。
这样,函数逐级别返回,OnCmdMsg 告诉 OnCommand 信息没有被办理, OnCommand 告诉OnWndMsg 信息没有被办理, OnWndMsg 告诉 WindowProc 信息没有被办理,于是 WindowProc 调用 DefWindowProc 进
行缺省办理。
本例子在第六步中,应用程序对ID_APP_ABOUT信息作了办理。
它找到办理函数CTApp::OnAbout,使用DispatchCmdMsg派发信息给该函数办理。
假如是 MDI 边框窗口,标准发送路径还有一个环节,该环节和第二、三、四步所波及的OnCmdMsg函数,将在下两节再次详细剖析。
命令信息的派发和信息的多次办理
命令信息的派发
如前 3.1 所述, CCmdTarget的静态成员函数DispatchCmdMsg用来派发命令信息给指定的命令目标的
信息办理函数。
static BOOL DispatchCmdMsg(CCmdTarget* pTarget,
UINT nID, int nCode,
AFX_PMSG pfn, void* pExtra, UINT nSig,
AFX_CMDHANDLERINFO* pHandlerInfo)
前方在讲 CCmdTarget时,提到了该函数。
这里叙述它的实现:
第一个参数指向办理信息的对象;第二个参数是命令ID;第三个是通知信息等;第四个是信息办理函数地点;第五个参
数用于寄存一些实用的信息,依据nCode的值表示不同的意义,比如当信息是WM_NOFITY ,指向一个NMHDR 结构(关于 WM_NOTIFY ,拜见 4.4.4.2 节通知信息的办理);第六个
参数表记信息办理函数原型;第七个参数是一个指针,指向
AFX_CMDHANDLERINFO结构。
前六个参数(除了第五个
外)都是向函数传达信息,第五个和第七个参数是双向的,
既向函数传达信息,也能够向调用者返回信息。
对于 AFX_CMDHANDLERINFO结构:
struct AFX_CMDHANDLERINFO
{
CCmdTarget* pTarget;
void (AFX_MSG_CALL CCmdTarget::*pmf)(void);
};
第一个成员是一个指向命令目标对象的指针,第二个成员是
一个指向 CCmdTarget成员函数的指针。
该函数的实现流程能够以下描绘:
第一,它检查参数pHandlerInfo能否空,假如不空,则用pTarget 和 pfn 填写其指向的结构,返回TRUE ;往常信息办理时传达来的 pHandlerInfo 空,而在使用 OnCmdMsg 来测试某个对象能否办理某条命令时,传达一个非空的pHandlerInfo 指针。
若返回 TRUE ,则表示能够办理那条信息。
假如 pHandlerInfo 空,则进行信息办理函数的调用。
它依据参数 nSig 的值,把参数 pfn 的种类变换为要调用的信息办理
函数的种类。
这类指针变换技术和前方叙述的 Windows 信息的办理是相同的。
信息的多次办理
假如信息办理函数不返回值,则 DispatchCmdMsg 返回
TRUE ;不然, DispatchCmdMsg 返回信息办理函数的返回值。
这个返回值沿着信息发送相反的路径逐级向上传达,使
得各个环节的OnCmdMsg和OnCommand获取返回的办理结果: TRUE 或许 FALSE ,即成功或许失败。
这样就产生了一个问题,假如信息办理函数存心返回一个FALSE ,那么不就传达了一个错误的信息?比如,OnCmdMsg函数获取FALSE返回值,就以为信息没有被处理,它将持续发送信息到下一环节。
确实是这样的,可是这
不是 MFC 的破绽,而是存心这么设计的,用来办理一些特
其余信息映照宏,实现同一个信息的多次办理。
往常的命令或许通知信息是没有返回值的(见 4.4.2 节的消息映照宏),不过一些特别的信息办理函数拥有返回值,这
类信息的信息办理函数是使用扩展信息映照宏映照的,比如:ON_COMMAND对应的ON_COMMAND_EX
扩展映照宏和对应的一般映照宏的参数个数相同,含义相同。
可是扩展映照宏的信息办理函数的原型和对应的一般映照
宏对比,有两个不同之处:一是多了一个UINT 种类的参数,此外就是有返回值(返回BOOL 种类)。
回首 4.4.2 章节,
范围映照宏 ON_COMMAND_RANGE的信息办理函数也有一个这样的参数,该参数在两处的含义是相同的,比如:命
令信息扩展映照宏 ON_COMMAND_EX定义的信息办理函数解说该参数是目前要办理的命令信息ID 。
有返回值的意义在于:假如扩展映照宏的信息办理函数返回FALSE ,则致使目前信息被发送给信息路径上的下一个信息目标办理。
综合来看, ON_COMMAND_EX宏有两个功能:
一是能够把多个命令信息指定给一个信息办理函数办理。
这
近似于 ON_COMMAND_RANGE 宏的作用。
可是,这里的多条信息的命令ID 或许控制子窗口ID 能够不连续,每条信息都需要一个 ON_COMMAND_EX 宏。
二是能够让几个信息目标办理同一个命令或许通知或许反射信息。
假如信息发送路径上较前的命令目标不办理信息或许办理信息后返回 FALSE ,则下一个命令目标将持续办理该信息。
对于通知信息、反射信息,它们也有扩展映照宏,并且上述
论断也适合于它们。
比如:
ON_NOTIFY对应的ON_NOTIFY_EX
ON_CONTROL对应的ON_CONTROL_EX
ON_CONTROL_REFLECT对应的
ON_CONTROL_REFLECT_EX
等等。
范围信息映照宏也有对应的扩展映照宏,比如:
ON_NOTIFY_RANGE对应的ON_NOTIFY_EX_RANGE ON_COMMAND_RANGE对应的
ON_COMMAND_EX_RANGE
使用这些宏的目的在于利用扩展宏的第二个功能:实现信息
的多次办理。
对于扩展信息映照宏的例子,拜见13.2..4.4 节和
节。
一些信息办理类的OnCmdMsg的实现
从以上阐述知道, OnCmdMsg 虚构函数在 MFC 命令信息的发送中饰演了重要的角色, CFrameWnd 的 OnCmdMsg 实现了 MFC 的标准命令信息发送路径。
那么,就产生一个问题:假如命令信息不送给边框窗口对象,
那么就不会有按标准命令发送路径发送信息的过程?答案是必
定的。
比如一个菜单被一个对话框窗口所拥有,那么,
菜单命令将送给 MFC 对话框窗口对象办理,而不是 MFC 边框窗口办理,自然不会和 CFrameWnd 的办理流程相同。
可是,有一点需要指出,一般标准的 SDI 和 MDI 应用程序,只有主边框窗口拥有菜单和工具条等用户接口对象,只有在
用户与用户接口对象进行交互时,才产生命令,产生的命令
必然是送给 SDI 或许 MDI 程序的主边框窗口对象办理。
下边,议论几个 MFC 类覆盖 OnCmdMsg 虚构函数时的实现。
这些类的 OnCmdMsg 或许可能是标准 MFC 命令信息路径的一
个环节,或许可能是一个独立的办理过程(对于此中的 MFC 窗
口类)。
从剖析 CView 的 OnCmdMsg实现开始。
CView 的 OnCmdMsg
CView::OnCmdMsg(UINT nID, int nCode, void* pExtra,
AFX_CMDHANDLERINFO* pHandlerInfo)
第一,调用CWnd::OnCmdMsg,结果是搜寻目前视的类和
基类的信息映照数组,搜寻次序是从基层到上层。
若某一层
实现了对命令信息nID 的办理,则调用它的实现函数;不然,调用 m_pDocument->OnCmdMsg,把命令信息送给文档类
办理。
m_pDocument是和目前视关系的文档对象指针。
如
果文档对象类实现了OnCmdMsg ,则调用它的覆盖函数;
不然,调用基类(比如 CDocument) 的 OnCmdMsg 。
接着,议论CDocument的实现。
CDocument的OnCmdMsg
BOOL CDocument::OnCmdMsg(UINT nID, int nCode,
void* pExtra,
AFX_CMDHANDLERINFO* pHandlerInfo)
第一,调用CCmdTarget::OnCmdMsg,致使目前对象(this)的类和基类的信息映照数组被搜寻,看能否有对应的信息处
理函数可用。
假如有,就调用它;假如没有,则调用文档模
板的 OnCmdMsg函数(m_pTemplate->OnCmdMsg)把消息送给文档模板办理。
MFC 文档模板没有覆盖OnCmdMsg ,致使基类CCmdTarget的OnCmdMsg被调用,看能否有文档模板类
或基类实现了抵信息的办理。
是的话,调用对应的信息办理
函数,不然,返回 FALSE 。
以前方的剖析知道,CCmdTarget 类的信息映照数组是空的,所以这里返回FALSE 。
CDialog 的 OnCmdMsg
BOOL CDialog::OnCmdMsg(UINT nID, int nCode,
void* pExtra,
AFX_CMDHANDLERINFO* pHandlerInfo)
调用 CWnd::OnCmdMsg,让对话框或其基类办理信息。
假如还没有办理,并且是控制信息或系统命令或非命令按钮,
则返回 FALSE ,不作进一步办理。
不然,调用父窗口的OnCmdmsg(GetParent()->OnCmdmsg)把信息送给父窗口办理。
假如仍旧没有办理,则调用目前线程的
OnCmdMsg(GetThread()->OnCmdMsg)把信息送给线程对象办理。
假如最后没有办理,返回FALSE 。
CMDIFrameWnd 的 OnCmdMsg
对于 MDI 应用程序, MDI 主边框窗口第一是把命令信息发送
给活动的 MDI 文档边框窗口进行办理。
MDI 主边框窗口对OnCmdMsg的实现函数的原型以下:
BOOL CMDIFrameWnd::OnCmdMsg(UINT nID, int nCode, void* pExtra,
AFX_CMDHANDLERINFO* pHandlerInfo)
假如有激活的文档边框窗口,则调用它的
OnCmdMsg(MDIGetActive ()->OnCmdMsg)把信息交给它进行办理。
MFC 的文档边框窗口类并无覆盖OnCmdMsg 函数,所以基类CFrameWnd的函数被调用,致使文档边框
窗口的活动视、文档边框窗口自己、应用程序对象挨次来进
行信息办理。
假如文档边框窗口没有办理,调用
CFrameWnd::OnCmdMsg把信息按标准路径发送,重复第
一次的步骤,可是对于 MDI 边框窗口来说不存在活动视,所以省却了让视办理信息的必需;接着让 MDI 边框窗口自己来办理信息,假如它还没有办理,则让应用程序对象进行信息办理──固然这是一个无用的重复。
除了 CView 、 CDocument和CMDIFrameWnd类,还有几个 OLE 有关的类覆盖了 OnCmdMsg 函数。
OLE 的办理本书暂不波及, CDialog::OnCmdMsg 将在对话框章节专项议论其详细实现。
一些信息办理类的OnCommand的实现
除了虚构函数OnCmdMsg ,还有一个虚构函数
OnCommand在命令信息的发送中据有重要地位。
在办理命
令或许通知信息时, OnCommand 被 MFC 窗口过程调用,而后它调用 OnCmdMsg 按必定路径传递信息。
除了 CWnd 类和一些OLE 有关类外, MFC 里主要还有 MDI 边框窗口实现了OnCommand 。
BOOL CMDIFrameWnd::OnCommand(WPARAM wParam, LPARAM lParam)
第一,假如存在活动的文档边框窗口,则使用AfxCallWndProc调用它的窗口过程,把信息送给文档边框
窗口来办理。
这将致使文档边框窗口的OnCmdMsg作以下的办理:
活动视办理信息→与视关系的文档办理信息→本文档边框窗
口办理信息→应用程序对象办理信息→文档边框窗口缺省处
理
任何一个环节假如办理信息,则不再向下发送信息,办理终
止。
假如信息仍旧没有被办理,就只有交给主边框窗口了。
第二,第一步没有办理命令,持续调用
CFrameWnd::OnCommand ,将致使 CMDIFrameWnd的OnCmdMsg被调用。
以前方的剖析知道,将再次把信息送
给 MDI 边框窗口的活动文档边框窗口,第一步的过程除了文档边框窗口缺省办理外都将被重复。
详细的办理过程见前文
的 CMDIFrameWnd::OnCmdMsg函数。
对于 MDI 信息,假如主边框窗口还不办理的话,交给
CMDIFrameWnd 的 DefWindowProc作缺省办理。
信息没有办理,返回FALSE 。
上述剖析综合了 OnCommand 和 OnCmdMsg 的办理,它们是在MFC 内部 MDI 边框窗口办理命令信息的完好的流程和标准的步骤。
整个办理过程再次表示了边框窗口在办理命令
信息时的中心作用。
从程序员的角度来看,能够以为整个标
准办理路径以下:
活动视办理信息→与视关系的文档办理信息→本文档边框窗
口办理信息→应用程序对象办理信息→文档边框窗口缺省处
理→ MDI 边框窗口办理信息→MDI边框窗口缺省办理
任何一个环节假如办理信息,不再向下发送信息,急办理终
止。
对控制通知信息的接收和办理
WM_COMMAND控制通知信息的办理
WM_COMMAND控制通知信息的办理和WM_COMMAND
命令信息的办理近似,可是也有不同之处。
第一,剖析办理WM_COMMAND控制通知信息和命令信息
的相像处。
如前所述,命令信息和控制通知信息都是由窗口
过程给OnCommand 办理(拜见CWnd::OnWndMsg 的实现),OnCommand 经过 wParam 和 lParam 参数划分是命令信息或通
知信息,而后送给 OnCmdMsg 办理(拜见
CWnd::OnCommnd的实现)。