MFC消息映射机制

合集下载

mfc的原理、机制与开发实例

mfc的原理、机制与开发实例

mfc的原理、机制与开发实例MFC(Microsoft Foundation Class)是微软公司开发的一套面向对象的应用程序框架,用于简化Windows操作系统上的图形用户界面(GUI)应用程序的开发。

MFC提供了一系列的类和函数,使开发者能够更加方便地创建、管理和操作窗口、对话框、控件等GUI元素。

MFC的原理和机制主要基于C++语言和Windows操作系统的API (Application Programming Interface)。

MFC的核心类是CObject类,所有的MFC类都是从CObject类派生而来的。

MFC使用了一种称为消息映射(Message Mapping)的机制来处理用户界面的事件和消息。

当用户进行操作时,例如点击按钮、输入文本等,Windows操作系统会生成相应的消息,并将其发送给应用程序。

MFC通过消息映射将这些消息与相应的处理函数关联起来,从而实现对用户操作的响应。

MFC的开发实例可以通过一个简单的计算器程序来说明。

首先,我们需要创建一个对话框,用于显示计算器的界面。

在MFC中,可以使用CDialog类来创建对话框。

然后,我们需要在对话框中添加一些控件,例如按钮、文本框等,用于用户输入和显示计算结果。

在MFC中,可以使用CButton、CEdit等类来创建这些控件。

接下来,我们需要处理用户的操作。

例如,当用户点击按钮时,我们需要执行相应的计算操作。

在MFC中,可以通过消息映射来实现。

首先,我们需要在对话框类中添加一个消息映射函数,用于处理按钮的点击事件。

然后,我们需要在消息映射函数中编写相应的代码,例如获取用户输入的数字、进行计算等。

最后,我们需要将消息映射函数与按钮关联起来,以便在用户点击按钮时调用相应的函数。

除了处理用户的操作,MFC还提供了许多其他功能,例如文件操作、数据库访问、图形绘制等。

开发者可以根据自己的需求选择相应的MFC类和函数来实现这些功能。

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消息机制
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原理结构说明

MFC原理结构说明MFC(Microsoft Foundation Classes)是一种在Windows平台上开发图形用户界面(GUI)的框架。

MFC提供了一组类、函数和宏,用于简化Windows应用程序开发过程。

本文将对MFC的原理和结构进行详细说明。

一、MFC的原理1. 类与对象:MFC使用面向对象的编程模型,所有的窗口、控件、消息处理程序等都是通过类来定义和创建的。

每个MFC应用程序都包含一个CWinApp类的对象,这个对象是整个应用程序的入口点。

2. 消息映射机制:在MFC中,消息是Windows事件的一种表示。

MFC使用消息映射机制来处理这些消息。

消息映射机制是程序员在类中定义的一种技术,它将特定消息与对应的消息处理函数关联起来。

当收到消息时,MFC会自动调用相应的消息处理函数进行处理。

3. 消息与事件:在MFC中,消息是Windows事件的抽象表示,而事件是用户界面中的交互行为。

MFC提供了一系列预定义的消息类型,如鼠标点击、按键、窗口关闭等,程序员只需要在类中覆盖对应的消息处理函数,就可以处理这些消息。

4. 窗口类和控件类:在MFC中,窗口类和控件类是界面元素的基础。

MFC提供了一组窗口类(如CWnd、CFrameWnd)和控件类(如CButton、CEdit),程序员可以通过继承这些类来创建自定义的窗口和控件。

5. 文档视图模型:MFC中引入了文档视图模型(Document-View Model)的概念,用于实现应用程序的数据和界面的分离。

文档类(CDocument)管理应用程序的数据,视图类(CView)用于显示数据,而框架窗口类(CFrameWnd)则用于协调文档和视图之间的交互。

二、MFC的结构1. 应用程序类(CWinApp):应用程序类是MFC应用程序的入口点,它派生自CWinApp类。

应用程序类负责初始化应用程序的环境,包括注册窗口类、创建主窗口、加载并运行消息循环等。

MFC消息映射机制过程

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 信息机制

mfc 信息机制

mfc 信息机制MFC信息机制MFC(Microsoft Foundation Class)是微软公司推出的一套用于Windows操作系统的C++类库,它为开发者提供了丰富的工具和组件,用于快速构建Windows应用程序。

在MFC中,信息机制是其重要特性之一,它提供了一种方便的方式来管理和传递应用程序中的消息。

一、消息机制的基本概念在MFC中,消息是指应用程序中发生的各种事件,比如鼠标点击、键盘输入、窗口关闭等。

消息机制是指MFC框架中的一套机制,用于处理和分发这些消息。

消息的处理过程包括两个关键组件:消息映射和消息处理函数。

1. 消息映射消息映射是指将消息和消息处理函数进行关联的过程。

通过在类的消息映射表中添加相应的消息和处理函数的映射关系,可以告诉MFC框架在收到某个消息时应该调用哪个函数进行处理。

消息映射表一般定义在类的声明中,使用宏来声明消息映射表的内容。

2. 消息处理函数消息处理函数是指用于处理特定消息的函数。

当MFC框架收到某个消息时,会根据消息映射表中的映射关系调用相应的消息处理函数。

消息处理函数可以是类的成员函数,也可以是全局函数,具体取决于消息映射表中的声明方式。

二、消息机制的应用场景消息机制在MFC中广泛应用于用户界面的交互和事件响应。

通过消息机制,开发者可以方便地处理用户的操作和系统的事件,实现各种功能和交互效果。

1. UI事件响应在MFC应用程序中,用户通过与界面上的控件进行交互来触发各种事件,比如按钮点击、菜单选择等。

通过消息机制,我们可以将这些事件与相应的处理函数进行关联,当用户触发某个事件时,可以执行相应的处理逻辑。

2. 窗口消息处理MFC中的窗口是指用户界面上的各种窗口元素,比如对话框、窗口、视图等。

窗口消息是指与窗口相关的各种事件,比如窗口创建、大小改变、关闭等。

通过消息机制,我们可以对窗口消息进行处理,实现窗口的初始化、布局、关闭等功能。

3. 自定义消息除了系统定义的消息类型,MFC还支持自定义消息。

MFC 消息映射机制详解

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的消息机制的实现原理和消息处理的过程

下面几节将分析MFC的消息机制的实现原理和消息处理的过程。

为此,首先要分析ClassWizard实现消息映射的内幕,然后讨论MFC 的窗口过程,分析MFC窗口过程是如何实现消息处理的。

1.消息映射的定义和实现1.MFC处理的三类消息根据处理函数和处理过程的不同,MFC主要处理三类消息:∙Windows消息,前缀以“WM_”打头,WM_COMMAND例外。

Windows消息直接送给MFC窗口过程处理,窗口过程调用对应的消息处理函数。

一般,由窗口对象来处理这类消息,也就是说,这类消息处理函数一般是MFC窗口类的成员函数。

∙控制通知消息,是控制子窗口送给父窗口的WM_COMMAND通知消息。

窗口过程调用对应的消息处理函数。

一般,由窗口对象来处理这类消息,也就是说,这类消息处理函数一般是MFC 窗口类的成员函数。

需要指出的是,Win32使用新的WM_NOFITY来处理复杂的通知消息。

WM_COMMAND类型的通知消息仅仅能传递一个控制窗口句柄(lparam)、控制窗ID和通知代码(wparam)。

WM_NOTIFY能传递任意复杂的信息。

∙命令消息,这是来自菜单、工具条按钮、加速键等用户接口对象的WM_COMMAND通知消息,属于应用程序自己定义的消息。

通过消息映射机制,MFC框架把命令按一定的路径分发给多种类型的对象(具备消息处理能力)处理,如文档、窗口、应用程序、文档模板等对象。

能处理消息映射的类必须从CCmdTarget类派生。

在讨论了消息的分类之后,应该是讨论各类消息如何处理的时候了。

但是,要知道怎么处理消息,首先要知道如何映射消息。

1.MFC消息映射的实现方法MFC使用ClassWizard帮助实现消息映射,它在源码中添加一些消息映射的内容,并声明和实现消息处理函数。

现在来分析这些被添加的内容。

在类的定义(头文件)里,它增加了消息处理函数声明,并添加一行声明消息映射的宏DECLARE_MESSAGE_MAP。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

由于工作需要,这几天学了一点MFC,在AFX里看到很多熟悉的东西,如类型信息,序列化,窗口封装和消息分派。

几乎每个界面库都必须提供这些基础服务,但提供的手法却千差万别。

MFC大量地借用了宏,映射表来实现,而VCL则更多的在语言级别上给与支持。

这其实是很容易理解的,因为C++是一个标准,不会因某个应用而随便扩展语言;相反Delphi完全由一个公司掌握,因此每支持一项新技术,变化最大的往往是语言本身。

学习MFC的代码,再对照VCL的实现,这真是一个很有意思的过程,其中可以看到两个框架在一些设计思想上是殊途同归的,所不同的是表现手法,以及封装的程度。

我计划将这段时间阅读MFC的心得写成一系列文章,其中可能会穿插与VCL的对比,不管你熟悉VCL还是MFC,通过这些文章或许可从另一个角度来看待自己熟悉的框架。

这是第一篇:消息分派。

消息处理函数表MFC和VCL在对消息进行封装的时候,都没有使用虚函数机制。

原因是虚函数带来了不必要的空间开销。

那么它们用什么来代替虚函数,即可减少空间浪费,也可实现类似虚函数的多态呢?让我们从一个例子开始。

假设父类ParentWnd处理了100个消息,并且将这100个处理函数声明为虚函数;此时有一个子类ChildWnd它只需要处理2个消息,另外98个交由ParentWnd默认处理,但是ChildWnd的虚表仍然占有100个函数指针,其中2个指向自己的实现,另外98个指向父类的实现,情况大概像下面这样:指向父类实现的函数指针浪费了空间,当控件类非常多的时候,这种浪费就非常明显。

因此必须走另一条路,将不必要的函数指针去掉,如下图所示:ChildWnd去掉函数指针之后,当有一个消息需要Fun100处理时,ChildWnd就束手无策了。

需要一个方法让ChildWnd能够找到父类的表,我们再对这个数据结构进行改进如下:现在看来好多了,如果ChildWnd有一个消息需要Fun1处理,则查找ChildWnd的MsgHandlers,找到Fun1函数指针调用之;如果需要Fun100处理,发现ChildWnd的MsgHandlers没有Fun100,则通过ParentTable找到父类的MsgHandlers继续查找。

如此一直查找,到最后再找不到,就调用DefWindowProc作默认处理。

MFC和VCL都是通过类似的方法实现消息分派的。

只是VCL有编译器的支持,直接将这个表放到VMT中,因此实现起来非常简单,只需在控件类里作如下声明:procedure WMMButtonDown(var Message: TWMMButtonDown); message WM_MBUTTONDOWN; TObject.Dispatch会将WM_MBUTTONDOWN正确分派到WMMButtonDown。

MFC就没有这么简单,它需要手工去构建这个表,如果一个类想处理消息,它必须声明一些结构和函数,代码类似这样:struct AFX_MSGMAP_ENTRY{UINT nMessage; // 消息AFX_PMSG pfn; // 消息处理函数};struct AFX_MSGMAP{const AFX_MSGMAP* pBaseMap; //指向基类的消息映射const AFX_MSGMAP_ENTRY* lpEntries; //消息映射表};class CMFCTestView : public CView{protected:void OnLButtonDown(UINT nFlags, CPoint point);private:static const AFX_MSGMAP_ENTRY _messageEntries[];protected:static const AFX_MSGMAP messageMap;virtual const AFX_MSGMAP* GetMessageMap() const;};仔细看_messageEntries和messageMap的声明,是不是和上面的图非常相似,接下来看看实现部分如何初始化这个表:const AFX_MSGMAP* CMFCTestView::GetMessageMap() const{ return & CMFCTestView::messageMap; }const AFX_MSGMAP CMFCTestView::messageMap ={ & CView::messageMap, & CMFCTestView::_messageEntries[0] };const AFX_MSGMAP_ENTRY CMFCTestView::_messageEntries[] ={{ WM_LBUTTONDOWN, (AFX_PMSG)&OnLButtonDown }{0, (AFX_PMSG)0 }};void CMFCTestView::OnLButtonDown(UINT nFlags, CPoint point){CView::OnLButtonDown(nFlags, point);}messageMap的第一个成员指向其父类的messageMap,即&CView::messageMap;第二个成员则指向下面的消息映射表;GetMessageMap是一个虚函数,显然是为了父类分派消息的时候能够找到正确的消息映射结构,后面会看到这一点。

_messageEntries数组为消息映射表,第一个元素处理WM_LBUTTONDOWN消息,其处理函数是OnLButtonDown,这个函数在CMFCTestView声明和实现;第二个元素标识了映射表的结尾。

现在,你想处理什么消息,都可以往_messageEntries里加新的元素并指定你的处理函数,只是如果每一个类都需要手工写这些代码,那将是很繁琐的事情;幸好C++有宏,可以用宏来作一些简化的代码,先将消息映射的声明用DECLARE_MESSAGE_MAP()表示,则类声明变成下面这样:class CMFCTestView : public CView{DECLARE_MESSAGE_MAP()};而实现部分,变成了下面这样:BEGIN_MESSAGE_MAP(CMFCTestView, CView)ON_WM_LBUTTONDOWN()END_MESSAGE_MAP()这就是MFC的消息映射宏,实际的代码和这里有一些出入,不过大体是差不多的,其核心作用就是构造消息处理函数表。

现在打开VC去看看那几个宏,是不是觉得其实很简单。

建好消息映射表后,接下来要看看消息如何流到指定的处理函数里。

消息流向我们可以认为消息的最初进入点是CWnd::WindowProc,在以后的文章会说明消息如何流到这个函数。

CWnd是所有窗口类的基类,CMFCTestView当然也是CWnd的子孙类。

WindowProc的代码很简单,调用OnWndMsg进行消息分派,如果没有处理函数,则调用DefWindowProc作默认处理:LRESULT CWnd::WindowProc(UINT message, WPARAM wParam, LPARAM lParam){// OnWndMsg does most of the work, except for DefWindowProc callLRESULT lResult = 0;if (!OnWndMsg(message, wParam, lParam, &lResult))lResult = DefWindowProc(message, wParam, lParam);return lResult;}最重要的是OnWndMsg成员函数,我将里面的代码作了简化,去掉了命令通知消息和一些优化代码,最终的代码如下:BOOL CWnd::OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult) {LRESULT lResult = 0;const AFX_MSGMAP* pMessageMap;//取得消息映射结构,GetMessageMap为虚函数,所以实际取的是CMFCTestView的消息映射pMessageMap = GetMessageMap();// 查找对应的消息处理函数for (pMessageMap != NULL; pMessageMap = pMessageMap->pBaseMap)if (message < 0xC000)if ((lpEntry = AfxFindMessageEntry(pMessageMap->lpEntries, message, 0, 0)) != NULL)goto LDispatch;... ...LDispatch://通过联合来匹配正确的函数指针类型union MessageMapFunctions mmf;mmf.pfn = lpEntry->pfn;int nSig;nSig = lpEntry->nSig;//nSig代表函数指针的类型,通过一个大大的Case来匹配。

switch (nSig){case AfxSig_bD:lResult = (this->*mmf.pfn_bD)(CDC::FromHandle((HDC)wParam));break;... ...case AfxSig_vwp:{CPoint point((DWORD)lParam);(this->*mmf.pfn_vwp)(wParam, point);break;}}return TRUE;}在代码中看到GetMessageMap的调用,根据前面的分析已经知道这是一个虚函数,所以实际调用到的是CMFCTestView::GetMessageMap(),也就是这里取到了CMFCTestView的消息映射结构。

接下来根据当前的消息表寻找对应的消息处理函数,调用AfxFindMessageEntry查找消息映射表,如果找不到就继续到基类去找,这就是For循环做的事情。

AfxFindMessageEntry使用内嵌汇编来提高查找的效率, VCL也是这样做的。

如果找到处理函数,则调用goto LDispatch;跳到下面的Case语句,根据nSig判断函数指针的实际类型,最后转换并调用之,此时我们的OnLButtonDown函数就被调用到了。

我们看到了Goto语句的使用,也看到下面大大的Case,这都是OO设计的禁忌,特别是下面的Case,为什么要用Case呢?这是由消息映射宏的设计决定的。

相关文档
最新文档