深入浅出MFC学习笔记 消息

摘要:
本章将深入讨论MFC的消息映射和命令传递机制。MFC指定消息传输的路由。消息将根据此路由传输。如果找不到目标,它将被移交给DefWindowProc。来自不同窗口的消息应由不同的窗口函数处理。WM_ COMMAND是来自菜单或工具栏的命令消息。它不参与消息处理。继续将其传递给CWinApp和默认消息处理函数。由于消息处理函数的类型不同,MFC使用AfxSig_来描述消息处理函数类型。

本章将会对MFC的消息映射和命令传递机制做深入探讨。

MFC规定了消息传递的路线,消息会按照这个路线传递下去,找不到归宿的话就交给DefWindowProc。

在产生窗口之前,如果我们在创建窗口时指定的窗口类为NULL时,MFC会自动注册五个默认的窗口类,每个窗口类有自己的窗口函数。不同窗口得到的消息应该交由不同的窗口函数来处理。所谓的命令传递机制是为了让消息的流动有线路可循,实现一个巨大的网,实现所有可能的路线。这就是所谓的消息映射图。

WM_COMMAND是来自菜单或工具栏,被称为命令消息。wParam记录着这一消息来自哪个菜单项目。

除了命令消息控件传给父窗口的消息,也是以WM_COMMAND类型的,但是它们被称为notification消息。

Commandtarget即命令的目的地。因此所有派生自CCmdTarget类的类都可以处理命令消息。

派生自CWnd的类可以处理一般的windows消息和COMMAND消息。

DECLARE_MESSAGE_MAP()

BEGIN_MESSAGE_MAP

ON_COMAMND()

END_MESSAGE()

这些宏实现了消息和消息处理函数的映射,不再介绍哦。

在BEGIN和END之间除了ON_COMMAND之外,还可以有其他的形式,标准的windows消息并不需要我们指定处理函数的名称。如:

ON_WM_CHAR();WM_CHAROnChar

ON_WM_CLOSE();WM_CLOSEOnClose

ON_WM_CREATE();WM_CREATEOnCreate

这些宏MFC已经定义好,将标准的消息和消息处理函数对应起来。

AFX_DAT,AFX_DATADEF,AFX_MSG_CALL和afx_msg一样现在还没有被使用。

虽然所有继承自CCmdTarget的类都可以处理命令消息,都应该有DECLARE_MESSAGE_MAP。。。但是CWinThread却没有。它不参与消息处理。因此CWinApp在填写消息映射表是就会跳过CWinThread。

DECLARE_MESSAGE_MAP(CWinApp,CCmdTarget);

消息映射表有C++多态的味道,但是MFC却没有使用多态来实现它,究其原因估计是多态会导致很大的负担。

前面的介绍中,以AfxWinProc作为起点,此处MFC仍以此作为开始,但是却省略了很多的细节。通常消息是在消息队列中等待窗口抓取,但是MFC安装了钩子,就可以提前抓取或抓取不是自己的消息。这是在所有派生自CWnd的对象创建之际发生的。如:

BoolCWnd::CreateEx()

{

。。。

AfxHookWindowCreate(this);

HWNDhWnd=::CreateWindowEx();

...

}

AfxHookWindowCreate安装了WH_CBT类型的钩子,任何窗口显示之前,注册的钩子函数会被调用。

细节不再深入介绍,只要知道以上这些干了些偷天换日的勾当,把注册窗口类时注册的窗口函数,更换为AfxWndProc。于是AfxWndProc便是DispatchMessage的目的地。之所以弄得这么复杂书上说是为了兼容什么3Dconstrols。不懂,暂且放这儿吧。记住结论就是了。

上面可以知道AfxWndProc是消息的源头,这在前面几张也提到过。在此函数内部会调用AfxClassWndProc,后者会调用pWnd->WindowProc();在整个MFC中拥有windowProc的类有CWnd,CControlBar,COleControl,CDialog......具体调用谁的WindowProc要看pWnd的类型。

在CWnd::windowProc中会调用OnWndMsg函数,它是用来分辨并处理消息的专职机构。如果是命令就交给OnCommand处理,如果是通知消息就交给OnNotify处理。之所以要区分命令消息和通知消息是因为它们的上溯路径并不是单纯的只往父类上去,可能有其他路径。而一般的windows消息却沿着直线上溯。

在OnCommand又调用了OnCmdMsg函数。具体调用哪个OnCommand,OnCmdMsg也是不定的,也得看this指针的类型。OnCmdMsg它是专门处理命令消息的函数。

boolCFrameWnd::OnCmdMsg(UINTnID,intnCode)

{

CView*pView=GetActiveView();

if(pView->OnCmdMsg(nID,nCode))//处理则返回否则继续传递。

returntrue;

if(CWnd::OnCmdMsg(nID,nCode))

returntrue;

CWinApp*pApp=AfxGetApp();

if(pApp->OnCmdMsg(nID,nCode)

returntrue;

returnfasle;

}

boolCView::OnCmdMsg(UINTnID,intnCode)

{

cout<<"CView::OnCmdMsg()"<<endl;

if(CWnd::OnCmdMsg(nID,nCode))

returntrue;

boolbHandled=false;

bHandled=m_pDocument->OnCmdMsg(nID,nCode);

returnbHandled;

}

BoolCDocument::OnCmdMsg(UINTnID,intnCode)

{

cout<<"CDocument::OnCmdMsg()"<<endl;

if(CCmdTarget::OnCmdMsg(nID,nCode))

returntrue;

returnfalse;

}

以上就是消息的传递路线,这里跟第三章模拟的命令传递路线是相同的,具体可以第三章。

OnCmdMsg是各类专门对付命令消息的函数。本类处理过后又会调用下一个类的OnCmdMsg,这样命令消息就会不断传递下去。

如果MDI主窗口接收到一个命令消息,主窗口会把消息传递给CMDIChildWnd子窗口。子窗口传递给它对应的视图,视图检查自己的消息映射表,如果没有找到对应项,将其传递给document。Document检查自己的消息映射表,找到对应项则调用该函数,消息传递结束。如果没有找到继续传递,document把该消息传递到documenttemplate对象。如果还是没有找到,则传回到view,view将其传递给MDI子窗口本身。继续传递给CWinApp,交给默认的消息处理函数。

在定义CRuntimeClass时,MessageMapEntries内定义了消息函数的指针类型,

typedefvoid(AFX_MSG_CALL

CCmdTarget:::*AFX_PMSG)(void);

此时消息处理函数指针类型为返回值为空,参数为空,这是不符合实际的,实际使用中会经过类型转换,使其可以接收参数和返回值。

由于消息处理函数的类型各异,MFC使用了AfxSig_来说明消息处理函数的类型。在找到某消息的消息处理函数之后,判断其类型再进行响应转换。

unionMessageMapFunctionsmmf;

mmf.pfn=lpEntry->pfn;

switch(lpEntry->nSig)

{

caseAfxSig_isg:

lResult=(this->*mmf.pfn_is)(LPTSTR)lParam);

break;

caseAfx_Sig_lwl:

lResult=(this->*mmf.pfn_lwl)(wParam,lParam);

break;

caseAfxSig_vv:

(this->*mmf.pfn_vv)();

break;

........

}

AfxSig_is代表参数为LPTSTR字符串,返回值为int.

Afx_lwl代表参数wiewParam和lParam。返回值为LRESULT。

Afx_vv代表参数和返回值都为void.

(this->*mmf.pfn_vv)();中的pfn_vv是unionMessageMapFunctions的一个成员。如

unionMessageMapFunctions

{

AFX_PMSGpfn;

bool(AFX_MSG_CALLCWnd::*pfn_bD)(CDC*);

void(AFX_MSG_CALLCWnd::*pfn_VV)(CDC*);

.............

};

注意MessageMapFunctions是union类型的哦。

真是佩服当年MFC开发人员的智慧!!!!!

免责声明:文章转载自《深入浅出MFC学习笔记 消息》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇MySQL高级知识(八)——ORDER BY优化HBase丢失数据的故障和原因分析下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

探究 Redis 4 的 stream 类型

 redis 2 10 月初,Redis 搞了个大新闻。别紧张,是个好消息:Redis 引入了名为 stream 的新数据类型和对应的命令,大概会在年底正式发布到 4.x 版本中。像引入新数据类型这样的变化在 Redis 的发展历史上非常罕见,所以称之为大新闻一点也不为过。至少很多介绍 Redis 的资料要跟着修订了。 背景 按作者的介绍,strea...

信息摘要算法之五:HMAC算法分析与实现

MAC(Message Authentication Code,消息认证码算法)是含有密钥散列函数算法,兼容了MD和SHA算法的特性,并在此基础上加上了密钥。因此MAC算法也经常被称作HMAC算法。 1、HMAC概述 HMAC算法首先它是基于信息摘要算法的。目前主要集合了MD和SHA两大系列消息摘要算法。其中MD系列的算法有HmacMD2、HmacMD4、...

【插件笔记】两款短小精悍的滚动插件

     首页图片轮播,消息的滚动显示,栏目的滚动,总是有那么一两款滚动插件适合你。但今天分享的不是有花哨效果的轮播插件,而是两款平实好用的滚动插件。   FlexSlider    GitHub地址:https://github.com/woothemes/FlexSlider/    FlexSlider灵活性很好,无论是大图片的轮播还是多个栏目的滚动...

拉仇恨!webhook + 企业微信给同事做了个代码提交监听工具

本文案例收录在 https://github.com/chengxy-nds/Springboot-Notebook 大家好,我是小富~ 最近接个任务,用webhook做了个代码提交监听功能,就是有人向远程仓库提交代码后,会在企业微信群内发送一条消息,类似 @XXX 在XXX时间,向XXX项目提交 XXXX 代码 这样的文案。 至于为啥要做这么个工具,没办...

SQL Server 检测到基于一致性的逻辑 I/O 错误 pageid 不正确

最近在查询SQL时遇到SQL文件错误,可能是文件数据已损坏。解决过程分享给大家。 问题描述 消息 824,级别 24,状态 2,第 1 行SQL Server 检测到基于一致性的逻辑 I/O 错误 pageid 不正确(应为 1:19741588,但实际为 0:0)。在文件 'D:analytics.MDF' 中、偏移量为 0x000025a772800...

MFC程序自动生成dump Windbg文件

  在客户机器上如何得到应该程序的详细出错信息, 这里使用drwtsn32,在应用程序崩溃的时候自动将调用栈的信息以文件形式保存在磁盘。   生成dump有drwtsn32, NTSD,CDB等多种工具,drwtsn32 于系统自带。   在项目中使用以下几个步骤: 1. 创建minidmp.h   minidmp.h #pragma once#inc...