精通MFC消息映射
mfc消息机制原理

MFC(Microsoft Foundation Classes)是一种用于开发Windows应用程序的C++类库,它建立在Win32 API之上,并提供了更高层次的抽象和封装。
在MFC中,消息机制是实现应用程序与用户交互和事件处理的基础。
MFC消息机制的原理如下:1.消息映射表:在MFC应用程序中,每个窗口类(如对话框类、视图类等)通常都有一个消息映射表(message map),用于将消息与相应的处理函数关联起来。
消息映射表是一个静态数据结构,通过DECLARE_MESSAGE_MAP宏进行声明,并在类的实现文件中使用BEGIN_MESSAGE_MAP和END_MESSAGE_MAP宏定义映射表的内容。
2.消息处理函数:每个消息映射表项将消息的ID(或者命令ID)与相应的消息处理函数绑定在一起。
消息处理函数是成员函数,由开发人员根据需要自行定义。
当相应的消息被触发时,系统会自动调用与该消息对应的处理函数。
3.消息循环:MFC应用程序在运行时通过消息循环(message loop)不断接收和分发消息。
消息循环负责从操作系统获取消息,并将消息派发给目标窗口的消息处理函数进行处理。
消息循环可以使用Run函数或AfxGetApp()->Run函数启动。
4.分发消息:当系统从消息队列中获取到一个消息后,会根据消息的目标窗口通过HWND来查找对应的CWnd对象,并调用该窗口的响应函数(如PreTranslateMessage、OnCmdMsg等)进行消息处理。
如果消息在目标窗口的消息映射表中找到了对应的处理函数,则将该消息转发给对应的处理函数进行处理。
5.消息处理:消息处理函数执行相应的逻辑,可以进行界面更新、控件操作、数据处理等操作。
处理函数的返回值通常是布尔型,表示是否终止消息的传递。
通过这种消息机制,MFC应用程序可以实现用户交互和事件处理的功能,使开发人员可以方便地处理窗口消息,响应用户操作,以及完成界面和数据之间的交互。
mfc 消息机制

mfc消息机制
MFC(Microsoft Foundation Class)是微软开发的一种面向对象的C++框架,用于Windows操作系统的应用程序开发。
MFC消息机制是MFC框架的核心之一,其基本原理是在窗口、控件等对象之间传递消息,以便处理事件和交互。
具体而言,MFC消息机制包括以下几个方面:1.消息循环:MFC使用一个消息循环来接受和处理Windows操作系统发送的Windows消息,处理完消息后将处理结果反馈给Windows操作系统。
2.消息映射:MFC中的控件和窗口都有一个关联的消息映射表,用于将Windows消息映射到应用程序代码中的相应处理函数上。
当某个控件或窗口收到消息后,根据消息类型在相应的消息映射表中查找对应的消息处理函数,并调用相应的处理函数处理消息。
3.消息类型:MFC处理的Windows消息类型包括键盘和鼠标消息、定时器消息、系统负载消息、窗口大小变化消息等等,具体的消息类型可以在MFC框架的文档中查找。
4.消息处理函数:MFC中的消息处理函数是C++成员函数,定义为afx_msg 修饰的函数,Windows消息处理函数命名时需要遵循一定的命名规则,例如OnPaint()函数用于处理绘图事件。
需要注意的是,MFC消息机制是针对Windows操作系统设计的,其他操作系统可能具有不同的消息机制。
此外,MFC框架已经不是微软推荐的最先进的应用程序开发框架,已经逐渐被其他框架和技术所取代,例如.NET Framework,WPF,UWP等。
MFC消息映射机制过程

MFC消息映射机制过程1:windows OS事件驱动策略基于3种消息。
标准消息、通告消息、命令消息。
2:“事件”就是“消息”,事件是有形形象的,是站在⼈类能理解的⾓度来定义的。
消息是⽆形抽象的,是站在OS能理解的⾓度来定义的。
3:我把按下⿏标左键这⼀事件转换成WM_LBUTOONDOWN消息来告诉OS我做了按下⿏标左键这了件事情。
现在OS知道了我做了按下⿏标左键这了件事情了,那么OS怎么处理呢?3.1:消息响应函数原型//{{AFX_MSG(CMyView)afx_msg void OnLButtonDown(UINT nFlags,CPoint point);//}}AFX_MSGDECLARE_MESSAGE_MAP()3.2:ON_WM_LBUTTONDOWN消息映射宏BEGIN_MESSAGE_MAP(CMyView, CView)//{{AFX_MSG_MAP(CMyView)ON_WM_LBUTTONDOWN()//}}AFX_MSG_MAP// Standard printing commandsON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint)ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint)ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview)END_MESSAGE_MAP()3.3:消息响应函数的定义void CMyView::OnLButtonDown(UINT nFlags, CPoint point){// TODO: Add your message handler code here and/or call defaultMessageBox("WM_LBUTTONDOWN");CView::OnLButtonDown(nFlags, point);}4:⾄此,我们从按下⿏标左键到看到如下图的效果,OS完成了对事件做出的反应。
MFC 消息映射机制详解

真正处理消息的是所谓的窗口过程(LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)),这个函数的参数记录了过程对应的窗口、消息的ID以及参数,在其内部开发者可以实现自己需要的消息处理功能。那消息分发是如何发送给窗口过程的呢?我们知道窗口创建过程中有一个注册窗口类的步骤,如下:
// 主消息循环:
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCE(IDC_WINDOWSP);
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
原文出处: Ocean2006
Windows程序和MFC程序是靠消息驱动的,他们对于消息的处理本质上是相同的。只是Windows程序对于消息处理的过程十分清晰明了,MFC程序则掩盖了消息处理的过程,以消息映射的方式呈现在开发者面前,使得开发消息的处理十分简单。用多了mfc就想对它的消息映射机制有一个本质的了解,下面将对消息映射做详细的分析。当然,在分析MFC消息映射之前首先对Windows程序的消息处理过程进行一个简单的描述。
MFC六大核心机制

MFC六大核心机制1.消息映射机制:MFC使用明确的消息映射机制来处理用户界面和系统事件。
应用程序通过重写消息映射函数来处理不同的消息事件,如鼠标点击、按键操作等。
消息映射机制使得开发者可以方便地响应和处理不同的用户交互动作。
2. 文档视图(Doc/View)体系:MFC采用了文档视图体系,将应用程序数据(文档)和用户界面(视图)分离。
文档表示应用程序的数据,视图代表用户界面,通过文档视图模式可以实现多视图的显示和操作。
开发者可以自定义文档类和视图类,通过它们来管理和展示数据。
3.对象序列化机制:对象序列化是指将对象的状态转换为可以存储或传输的格式,以便于在不同的环境中恢复对象的状态。
MFC提供了强大的对象序列化支持,可以方便地对应用程序的数据进行存储和加载。
开发者只需将需要序列化的成员变量标记为可序列化,并实现相关的序列化函数即可实现数据的持久化。
4.多线程支持:MFC提供了多线程支持,使得应用程序可以在多个线程中同时执行任务。
开发者可以使用MFC提供的线程类来创建和管理线程,并通过消息机制进行线程间的通信。
多线程支持有助于提高应用程序的性能和响应能力。
MFC的运行时类是一组用于封装常用功能的类,包括字符串操作、容器类、文件I/O等。
这些类提供了方便、高效的操作接口,减少了开发者对底层操作的依赖。
开发者可以直接使用MFC提供的运行时类来简化开发过程。
6.扩展性:MFC提供了丰富的扩展性机制,包括自定义控件、自定义对话框、自定义视图等。
开发者可以通过派生已有的MFC类来创建自定义的控件或界面,以满足特定的应用程序需求。
扩展性机制使得开发者可以充分发挥自己的创造力和想象力,实现更加个性化的应用程序。
总结:MFC六大核心机制为开发者提供了丰富的类和功能,使得开发Windows图形界面应用程序更加简单和高效。
通过消息映射机制、文档视图体系、对象序列化机制、多线程支持、运行时类和扩展性机制,开发者可以轻松地实现各种应用程序的需求,并提供更好的用户体验。
MFC消息映射及消息处理函数原型

afx_msg void memberFxn();
ON_EN_SETFOCUS(<id>, <memberFxn>)
afx_msg void memberFxn();
ON_EN_UPDATE(<id>, <memberFxn>)
afx_msg void memberFxn();
ON_NOTIFY_EX_RANGE(<wNotifyCode>, <id>, <idLast>, <memberFxn>)
afx_msg BOOL memberFxn(UINT, NMHDR*, LRESULT*);
ON_NOTIFY_RANGE(<wNotifyCode>, <id>, <idLast>, <memberFxn>)
afx_msg void memberFxn();
ON_STN_ENABLE(<id>, <memberFxn>)
afx_msg void memberFxn();
标准Windows消息( WM_xxx )的对应规则:
消息映射
对应处理函数原型
ON_WM_ACTIVATE()
afx_msg void OnActivate(UINT, CWnd*, BOOL);
afx_msg void memberFxn(UINT);
ON_CONTROL_REFLECT(<wNotifyCode>, <memberFxn>)
afx_msg void memberFxn();
消息映射及MFC入门

MFC消息映射及MFC入门一、MFC消息映射机制在前面Win32Class工程中,我们进行了Win32环境下的“消息映射”。
其实,通过前面的过程,我们已经不知不觉的接触到了MFC消息映射的核心。
MFC环境下的消息映射,其原理和我们讲解过的Win32下的消息映射是类似的。
简单地讲,就是让程序员指定要某个MFC类(有消息处理能力的类)处理某个消息。
MFC提供了工具ClassWizard来帮助实现消息映射,在处理消息的类中添加一些有关消息映射的内容和处理消息的成员函数。
程序员负责编写消息处理函数的代码,实现所希望的功能。
可以通过如下的3个重要的宏来实现MFC消息映射,这些宏功能强大,其实现相对也比较复杂。
这里只要求我们会用就可以。
稍后我们会用其实际代码替换这些宏,就能理解了。
●DECLARE_MESSAGE_MAP:初始化消息映射表,实际上是给所在类添加几个用于消息处理的静态成员变量和静态或虚拟函数。
●BEGIN_MESSAE_MAP:开始消息映射。
●END_MESSAE_MAP:结束消息映射。
其他常见的、用于实现MFC消息的宏还有:●前缀为“ON_WM_”的宏:用于Windows消息的宏(不带参数)如:ON_WM_PAINT()把消息WM_PAINT映射到OnPaint函数。
●ON_COMMAND宏:通过参数指定命令ID和消息处理函数。
如ON_COMMAND(ID_EDIT_PASTE, OnEditPaste),其中第二个参数OnEditPaste 的原型说明为:void CView::OnEditPaste()。
●ON_UPDA TE_COMMAND_UI宏:用于更新菜单的状态。
●前缀为”ON_”控件通知消息宏:这类宏可能带有三个参数,如ON_CONTROL,就需要指定控制窗口ID,通知码和消息处理函数;也可能带有两个参数,如具体处理特定通知消息的宏ON_BN_CLICKED、ON_LBN_DBLCLK、ON_CBN_EDITCHANGE等,需要指定控制窗口ID和消息处理函数。
关于MFC消息映射机制剖析

关于MFC消息映射机制剖析软采用了所谓的消息映射机制,来完成不同对象之间消息的传递,本文就MFC9.0源码进行分析,大致讲解MFC的消息映射机制。
步入正题,在AfxWinMain() 函数中,当MFC框架初始化完成后,即pThread->InitInstance() 执行完成,就开始进行消息循环,入口函数是pThread->Run():[cpp]view plaincopy1.// Perform specific initializations2.if (!pThread->InitInstance())// MFC初始化框架3.{4.if (pThread->m_pMainWnd != NULL)5. {6. TRACE(traceAppMsg, 0, "Warning: Destroying non-NULL m_pMainWnd\n");7. pThread->m_pMainWnd->DestroyWindow();8. }9. nReturnCode = pThread->ExitInstance();10.goto InitFailure;11.}12.nReturnCode = pThread->Run();// 进入消息循环执行CWinApp:: Run():[cpp]view plaincopy1.// Main running routine until application exits2.int CWinApp::Run()3.{4.if (m_pMainWnd == NULL && AfxOleGetUserCtrl())5. {6.// Not launched /Embedding or /Automation, but has no main window!7. TRACE(traceAppMsg, 0, "Warning: m_pMainWnd is NULL in CWinApp::Run -quitting application.\n");8. AfxPostQuitMessage(0);9. }10.return CWinThread::Run();11.}执行CWinThread::Run():[cpp]view plaincopy1.// main running routine until thread exits2.int CWinThread::Run()3.{4. ASSERT_VALID(this);5. _AFX_THREAD_STATE* pState = AfxGetThreadState();6.7.// for tracking the idle time state8.BOOL bIdle = TRUE;9.LONG lIdleCount = 0;10.11.// acquire and dispatch messages until a WM_QUIT message is received.12.GetMessage:从系统获取消息,将消息从系统中移除,属于阻塞函数。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
MFC是微软基础类库的简称,是微软公司实现的一个c++类库,主要封装了大部分的windows API函数,消息系统对于一个win32程序来说十分重要,它是一个程序运行的动力源泉。
一个消息,是系统定义的一个32位的值,他唯一的定义了一个事件,向Windows发出一个通知,告诉应用程序某个事情发生了。
众所周知,windows是基于消息驱动的,作好消息处理是WINDOWS编程的关键任务之一,用VC制作WINDOWS程式同样离不开消息的处理。
虽然VC++6的类向导可以完成绝大部分工作,但不幸的是,它并不能完成所有的工作。
这就要求我们对 VC中消息的处理有一个比较清淅的认识。
只有这样才可能在必要的时候亲自动手完成一些复杂的消息映射处理。
在MFC中消息是通过一种所谓的消息映射机制来处理的。
其实质是一张消息及其处理函数的一一对应表以及分析处理这张表的应用框架内部的一些程序代码.这样的好处是可以避免像早期的 SDK编程一样需要罗列一大堆的CASE语句来处理各种消息.由于不同种类的消息其处理方法是不同的,所以我们有必要先弄清楚 WINDOWS消息的种类。
背景:WINDOWS 消息的种类WINDOWS中消息主要有以下三种类型:1、标准的WINDOWS消息:这类消息是以WM_为前缀,不过WM_COMMAND例外。
例如: WM_MOVE、WM_QUIT等.2、命令消息:命令消息以WM_COMMAND为消息名.在消息中含有命令的标志符ID,以区分具体的命令.由菜单,工具栏等命令接口对象产生.3、控件通知消息:控件通知消息也是以WM_COMMAND为消息名.由编辑框,列表框,子窗口发送给父窗口的通知消息.在消息中包含控件通知码.以区分具体控件的通知消息.其中标准的WINDOWS消息及控件通知消息主要由窗口类即直接或间接由CWND类派生类处理.相对标准WINDOWS消息及控件通知消息而言,命令消息的处理对象范围就广得多.它不仅可以由窗口类处理,还可以由文档类,文档模板类及应用类所处理。
方法:不同种类消息的映射方法。
在以上三种消息中,标准的WINDOWS消息映射是相当简单的。
可直接通过类向导完成不同消息的映射处理,所以不在本文讨论之列。
凡是从CcmdTarget类派生的类都可以有消息映射.消息映射包括如下两方面的内容: 在类的定义文件中(.H)中加上一条宏调用:1.DECLARE_MESSAGE_MAP()通常这条语句中类定义的最后.在类的实现文件(.CPP)中加上消息映射表:1.BEGIN_MESSAGE_MAP(类名,父类名)2.………..3.消息映射入口项.4.……….5.END_MESSAGE_MAP( )幸运的是除了某些类(如没有基类的类或直接从CobjectO类派生的类)外.其它许多类均可由类向导生成.尽管生成的类只是一个框架,需要我们补充内容.但消息映射表已经为我们加好了.只是入口项有待我们加入.命令消息映射入口项是一个ON_COMMAND的宏.比如文件菜单下的"打开…"菜单(ID值为ID_FILE_OPEN)对应的消息映射入口项为:1.ON_COMMAND(ID_FILE_NEW,OnFileOpen)加入消息映射入口项之后需要完成消息处理函数.在类中消息处理函数都是类的成员函数,要响应一个消息,就必须定义一个该消息的处理函数.定义一个消息处理函数包括以下三方面的内容.∙在类定义中加入消息处理函数的函数原型(函数声明)∙在类的消息映射表中加入相应的消息映射入口项.∙在类的实现中加入消息处理函数的函数体.需要说明的是消息处理函数的原型一定要以afx_msg打头.比如:1.afx_msg OnFileOpen();// 函数原型作为约定.消息处理函数一般以On打头但有时我们可能想用一个消息处理函数来处理一批消息。
这时类向导就无能为力了。
我们必须手工加入消息映射来完成这种工作。
可用如下方法实现:首先在处理该消息所在类的实现文件(亦即.CPP)中加入的消息映射入口:1....2.BEGIN_MESSAGE_MAP(CMyApp, CWinApp)3.file://{{AFX_MSG_MAP(CMyApp)4....5.file://}}AFX_MSG_MAP6.ON_COMMAND_RANGE(ID_MYCMD_ONE, ID_MYCMD_TEN, OnDoSomething)7.END_MESSAGE_MAP( )8....粗体标志的语句是我们加入的语句(以后约定我们加入的语句均用粗体标志).其中我们使用了宏ON_COMMAND_RANGE来实现从命令消息 ID_MYCMD_ONE到 ID_MYCMD_TEN都由OnDoSomthing一个消息函数处理.注意.ID_MYCMD_ONE到 ID_MYCMD_TEN的ID值一定要连续.且ID_MYCMD_ONE值一般较小.完成上述工作之后我们还需要在该类的头文件(亦即.H)中加入消息处理函数的申明:1.// Generated message-map functions2.protected:3.file://{{AFX_MSG(CMyApp)4....5.file://}}AFX_MSG6.afx_msg void OnDoSomething( UINT nID );7.DECLARE_MESSAGE_MAP()8.由于这不是VC类向导加入的函数申明,所以放在了//}}AFX_MSG之外.注意这个消息处理函数有一个UINT类型参数.而处理单一命令的消息处理函数一般是没有参数(除更新用户接口对象状态命令消息处理函数).这个参数的主要作用是提供用户选择的命令的ID值.最后要做的工作就是在该类的实现文件中实现该消息处理函数. 同样,有时我们也想使用一个消息处理函数处理一批更新用户接口对象状态命令消息.方法同上: 首先在.CPP文件中加入语句如下:1....2.BEGIN_MESSAGE_MAP(CMyApp, CWinApp)3.file://{{AFX_MSG_MAP(CMyApp)4....5.file://}}AFX_MSG_MAP6.ON_UPDATE_COMMAND_UI_RANGE (ID_MYCMD_ONE, ID_MYCMD_TEN, OnUpdateSomething)7.END_MESSAGE_MAP( )8. ...在该类的头文件(亦即.H)中加入消息处理函数的申明:1.// Generated message-map functions2.protected:3.file://{{AFX_MSG(CMyApp)4....5.file://}}AFX_MSG6.afx_msg void OnUpdateSomething( CcmdUI * pcmdui );7.DECLARE_MESSAGE_MAP()请各位注意了,仔细的读者已经注意到这里的消息处理函数并未像命令消息处理函数需要一个额外的UINT类型的参数.原因在于pcmdui中已包含了此信息.所以不再需要这个参数了.最后不要忘了完成函数体!关于命令消息就讨论到这个地方.接下来讨论控件通知消息.控件通知消息相对而言就复杂一点了.限于篇幅不能一一涉及.这里我们仅讨论WM_NOTIFY消息的处理.WM_NOTFY产生的原因如下。
在WINDOWS3.X中控件通知它们父窗口,如鼠标点击,控件背景绘制事件,通过发送一个消息到父窗口.简单的通知仅发送一个WM_COMMAND消息.包含一个通知码(比如BN_CLICKED)和一个在wParam中的控件ID及一个在lPraram中的控件句柄.因为wParam 和lParam均被使用.就没有方法传送其它的附加信息了.比如在BN_CLICKED 通知消息中.就没有办法发送关于当鼠标点击时光标的位置信息.在这种情况下就只能使用一些特殊的消息.包括:WM_CTLCOLOR,WM_VSCROLL, WM_HSCROLL等等.值得一提的是这些消息能被反射回发送它们的控件.就是所谓的消息反射.有兴趣的读者请参阅有关专著.在WIN32中同样可以使用那些在WINDOWS3.1中使用的通知消息.不过不像过去通过增加特殊目的的消息来为新的通知发送附加的数据.而是使用一个叫 WM_NOTIFY的消息,它能以一个标准的风格传送大量的附加数据.WM_NOTIFY 消息包含一个存在wParam中的发送消息控件的ID和一个存在 lParam中的指向一个结构体的指针.这个结构可能是NMHDR结构体.也可能是第一个成员是NMHDR的更大的结构.因为NMHDR是第一个成员,所以指向这个结构的指针也可以指向NMHDR.在许多情况下,这个指针将指向一个更大的结构,当你使用时必需转换它.只有很少的通知消息.比如通用通知消息(它的名字以NM_打头),工具提示控件的 TTN_SHOW和TTN_POP实际上在使用NMHDR结构.NMHDR结构包含了发送消息控件的句柄,ID及通知码(如TTN_SHOW),其格式如下:1.Typedef sturct tagNMHDR{2.HWND hwndFrom;3.UINT idFrom;4.UINT code;5.} NMHDR;对TTN_SHOW消息而言,code成员的值将设为TTN_SHOW.类向导可以创建ON_NOTIFY消息映射入口并为你提供一个处理函数的框架.来处理WM_NOTIFY类型的消息.ON_NOTIFY消息映射宏有如下语法.1.ON_NOTIFY(wNotifyCode,id,memberFxn)数意义如下:∙wNotifyCode:要处理的通知消息通知码。
比如:LVN_KEYDOWN.∙Id:控件标识ID.∙MemberFxn:处理此消息的成员函数.此成员函数必需有如下的原形申明:1.afx_msg void memberFxn( NMHDR * pNotifyStruct, LRESULT * result);比如:假设你想成员函数OnKeydownList1处理ClistCtrl(标识ID=IDC_LIST1)的LVN_KEYDOWN消息,你可以使用类向导添加如下的消息映射:1.ON_NOTIFY( LVN_KEYDOWN, IDC_LIST1, OnKeydownList1 )在上面的例子中,类向导提供如下函数:1.void CMessageReflectionDlg::OnKeydownList1(NMHDR* pNMHDR, LRESULT* pResult)2.{3.LV_KEYDOWN* pLVKeyDow = (LV_KEYDOWN*)pNMHDR;4.// TODO: Add your control notification handler5.// code here6.*pResult = 0;7.}这时类向导提供了一个适当类型的指针.你既可以通过pNMHDR,也可以通过 pLVKeyDow 来访问这个通知结构。