• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

VC++消息映射机制 WindowProc的函数wincore.cpp

武飞扬头像
文君呀!
帮助1

目录

消息映射机制

WindowProc的函数(wincore.cpp)

OnWndMsg 函数(wincore.cpp)

OnWndMsg函数的处理过程是:

接上:VC 类向导

接下:VC OnWndMsg 函数(wincore.cpp)


消息映射机制

可以浏览一下Draw项目CDrawView的头文件和源文件,可以发现在为视类增加一个鼠标左键按下这一消息响应函数之后,在文件中增加了三处代码。

(1)消息响应函数原型在CDrawView类的头文件(DrawView.h)中,有如下所示代码。

  1.  
    // 生成的消息映射函数
  2.  
    protected:
  3.  
    DECLARE_MESSAGE_MAP()
  4.  
    public:
  5.  
    afx_msg void OnLButtonDown(UINT nFlags, CPoint point);

如上所示这段代码中,在OnLButtonDown函数声明的前面有一个afx_msg限定符,这是一个。该宏表明这个函数是一个消息响应函数的声明

(2)ON_WM_LBUTTONDOWN消息映射宏在CDrawView类的源文件(DrawView.cpp)中,有下所示代码。

  1.  
    BEGIN_MESSAGE_MAP(CDrawView, CView)
  2.  
    // 标准打印命令
  3.  
    ON_COMMAND(ID_FILE_PRINT, &CView::OnFilePrint)
  4.  
    ON_COMMAND(ID_FILE_PRINT_DIRECT, &CView::OnFilePrint)
  5.  
    ON_COMMAND(ID_FILE_PRINT_PREVIEW, &CView::OnFilePrintPreview)
  6.  
    ON_WM_LBUTTONDOWN()
  7.  
    END_MESSAGE_MAP()

上述例5-4所示代码中,BEGIN_MESSAGE_MAPEND_MESSAGE_MAP()这两个宏之间定义了CDrawView类的消息映射表,其中有一个ON_WM_LBUTTONDOWN消息映射宏,这个宏的作用就是把鼠标左键按下消息(WM_LBUTTONDOWN)与一个消息响应函数关联起来(在本例中是把WM_LBUTTONDOWN消息与OnLButtonDown函数关联起来)。通过这种机制,一旦有消息产生,程序就会调用相应的消息响应函数来进行处理。

(3)消息响应函数的定义在CDrawView类的源文件(DrawView.cpp)中,可以看到OnLButtonDown函数的定义。

  1.  
    void CDrawView::OnLButtonDown(UINT nFlags, CPoint point)
  2.  
    {
  3.  
    // TODO: 在此添加消息处理程序代码和/或调用默认值
  4.  
    MessageBox(L"view clicked");
  5.  
    CView::OnLButtonDown(nFlags, point);
  6.  
    }

经过以上分析可以知道,一个 MFC 消息响应函数在程序中有三处相关信息:函数原型函数实现,以及用来关联消息和消息响应函数的宏。在头文件中使用afx_msg宏来表明这是一个消息响应函数原型的声明,在源文件中有两处:一处是在BEGIN_MESSAGE_MAP(…)END_MESSAGE_MAP()这两个宏之间的消息映射宏 ON_WM_LBUTTOND OWN();另一处是源文件中的消息响应函数的实现代码。

在讲述消息循环时曾介绍过,当有消息产生时,操作系统会把这条消息放到应用程序的消息队列中,应用程序通过 GetMessage 函数从这个队列中取出一条具体的消息,并通过 DispatchMessage 函数把消息交给操作系统,后者调用应用程序的窗口过程,即窗口过程函数 WndProc 进行处理。该函数利用 switch-case 结构来对消息进行判别并分类处理。然而,我们看到在 MFC 程序中,并不是按照这种途径进行处理的,只要遵照上述步骤,定义了与消息有关的三处信息后,就可以实现消息的响应处理。MFC中采用的这种消息处理机制称为MFC消息映射机制

实际上,消息路由可以有多种实现方式。其中一种可能的实现方式是,在基类中针对每种消息定义一个虚函数。当子类需要对某个消息进行处理时,只需要重写基类相应的虚函数即可。当在程序中调用这个函数时,根据多态性原理,如果子类重写了该函数,就调用子类的这个函数,否则就调用父类的相应函数。通过这种方式也可以完成消息的路由。这样做从原理上讲是没有问题的,但是从编程角度讲,是不可取的。

为什么不可取?因为虚函数必须由一个虚函数表(vtable)来实现。在应用程序中使用的每个派生类,系统都要为它们分配一个 vtable,并且不管基类中虚函数是否在派生类中被重写,这个vtable表都要为基类的每一个虚函数提供一个4字节的输入项。而我们知道,MFC中类的派生层次有很多,这样做将使MFC类及其派生类背着一个很大的虚拟函数表的包袱,这对内存资源是一种浪费。而且,每次扫描虚拟函数表也非常消耗时间,这种定义虚拟函数的做法显然是不合适的。所以,MFC没有采用虚拟函数这种机制,而是采用一种称之为消息映射的机制来完成消息路由

MFC 消息映射机制的具体实现方法是:在每个能接收和处理消息的类中,定义一个消息和消息函数静态对照表,即消息映射表。在消息映射表中,消息与对应的消息处理函数指针是成对出现的。某个类能处理的所有消息及其对应的消息处理函数的地址都列在这个类所对应的静态表中。当有消息需要处理时,程序只要搜索该消息静态表,查看表中是否含有该消息,就可知道该类能否处理此消息。如果能处理该消息,那么依照静态表同样能很容易找到并调用对应的消息处理函数。

下面让我们看看MFC消息映射机制的实际实现过程。MFC在后台维护了一个窗口句柄与对应的C 对象指针的对照表。以本例中的CDrawView类为例,与CDrawView对象相关的有一个窗口,窗口当然有它的窗口句柄,该句柄与CDrawView对象的一个指针(即CDrawView*)存在着一个一个地对应关系,在窗口句柄与 C 对象对照表中就维护了这种对应关系。当收到某一消息时,消息的第一个参数就指明该消息与哪个窗口句柄相关,通过对照表,就可以找到与之相关的C 对象指针。把这个指针传递给应用程序框架窗口类的基类,后者会调用一个名为WindowProc的函数。该函数的定义位于wincore.cpp文件,代码如下所示。

WindowProc的函数(wincore.cpp)

  1.  
    LRESULT CWnd::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
  2.  
    {
  3.  
    // OnWndMsg does most of the work, except for DefWindowProc call
  4.  
    LRESULT lResult = 0;
  5.  
    if (!OnWndMsg(message, wParam, lParam, &lResult))
  6.  
    lResult = DefWindowProc(message, wParam, lParam);
  7.  
    return lResult;
  8.  
    }

转到WindowProc函数的声明处,我们可以发现它是一个虚函数。在这个函数的内部调用了一个 OnWndMsg 函数,真正的消息路由,也就是消息映射就是由此函数完成的。OnWndMsg函数的定义也位于wincore.cpp文件中,部分代码如下所示。

	if (!OnWndMsg(message, wParam, lParam, &lResult))

OnWndMsg 函数(wincore.cpp

连接:VC OnWndMsg 函数(wincore.cpp)

OnWndMsg函数的处理过程是:

判断消息是否有消息响应函数

判断方法是在消息映射表中进行查找。

如果找到了,则直接通过传递给WindowProc函数的窗口子类指针调用子类中的消息响应函数。

如果在子类中没有找到消息响应函数,那么就交由基类进行处理。

而消息映射表就是通过头文件中的DECLARE_MESSAGE_MAP()宏,以及源文件中的BEGIN_MESSAGE_MAP(…)END_MESSAGE_MAP()宏构建的,在这两个宏之间的每个消息映射宏都将作为消息映射表的一个条目。

通过以上步骤,MFC就实现了具体的消息映射,从而完成对消息的响应。

接上:VC 类向导

接下:VC OnWndMsg 函数(wincore.cpp)

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhggeakg
系列文章
更多 icon
同类精品
更多 icon
继续加载