一、开篇引论

熟悉Win32开发的朋友,应该非常了解它的基本组成和流程

1. WinMain:书写窗口类(WNDCLASS) -> 注册窗口类 -> 创建窗口 -> 显示窗口和更新窗口 -> 消息循环

2. WndProc(回调函数):消息处理函数,由windows操作系统自行调用

而MFC呢,就是用c++面向对象的编程思想将这些主要成分封装到各个基本类中,由于封装得很隐蔽,所以学习它的难度就大大增加了。今儿,我就带着大家一起来剖析一下MFC的来龙去脉

在看后面两点之前,先上一份剖析MFC最简单的代码(MFC版的Hello):

1. Hello.h:

只有CMyApp和CMainWindow两个类,它们分别是CWinApp、CFrameWnd的子类,这两个基类有分别封装了WinMain和消息映射机制(相当于WndProc的消息处理)

//Hello.h

//封装了Win32的WinMain函数的处理过程
class CMyApp : public CWinApp
{
public:
virtual BOOL InitInstance ();
}; //实现了MFC的消息机制
class CMainWindow : public CFrameWnd
{
public:
CMainWindow (); protected:
afx_msg void OnPaint ();
DECLARE_MESSAGE_MAP ()//消息映射的声明
};

2. Hello.cpp

//Hello.cpp

#include <afxwin.h>
#include "Hello.h" CMyApp myApp; /////////////////////////////////////////////////////////////////////////
// CMyApp member functions BOOL CMyApp::InitInstance ()
{
m_pMainWnd = new CMainWindow;
m_pMainWnd->ShowWindow (m_nCmdShow);
m_pMainWnd->UpdateWindow ();
return TRUE;
} /////////////////////////////////////////////////////////////////////////
// CMainWindow message map and member functions //消息映射
BEGIN_MESSAGE_MAP (CMainWindow, CFrameWnd)
ON_WM_PAINT ()
END_MESSAGE_MAP () CMainWindow::CMainWindow ()
{
Create (NULL, _T ("The Hello Application"));
} void CMainWindow::OnPaint ()
{
CPaintDC dc (this); CRect rect;
GetClientRect (&rect); dc.DrawText (_T ("Hello, MFC"), -1, &rect, DT_SINGLELINE |DT_CENTER | DT_VCENTER);
}

今天主要利用这两份源代码来剖析MFC的"WinMain"和消息机制,下面进入主题(我就不说什么F话了,直接切入^_^)

二、MFC的"WinMain函数"跑哪儿去了呢?

要想找到它,我给大家介绍一种很有效的方式:

1. 如果你是VC++6.0,就用"Call Stack"(下图红色框圈住的按钮)

2. 如果是VS2008,就用"堆栈帧"(在调试模式下,会出现)

我这里使用的是vc++6.0:

1. 先在OnPaint函数(处理WM_PAINT消息)那儿设置一个端点

2. 键入F5进入调试模式,然后点击"Call Stack",得到的结果如下:

接下来需要做的工作就是一一跟踪这些函数,跟踪一会儿你就能很快了解到MFC中关于Win32的各个实现细节

在这里,由于篇幅的限制,我就直接明述跟踪结果(你可以自行按照上述方法跟踪,这样才有助于深入理解):

1.  全局变量CMyApp myApp;

2. _tWinMain

3. 全局变量myApp的InitInstance()函数

4. 窗口类的注册

5. 创建窗口

6.  显示、更新窗口(还是调用myApp的InitInstance()函数)

7. 进入WndProc,处理消息响应

这里我仅仅将大致的过程贴出来,给你一个大致思路,具体的需要你自己去调试、探究,这样的难度应该就小很多了

三、MFC的消息映射机制

这是MFC的精华所在,它将Win32的消息处理(以WM_开头的消息)过程 映射为 类函数成员函数的处理过程,这样才能符合面向对象的编程思想。其实,它就是使用一大堆宏来实现一种类似于c++的多态机制,因此,要想深入了解这个消息机制,我们必须剖析这些宏:

DECLARE_MESSAGE_MAP ()//消息映射的声明

//消息映射
BEGIN_MESSAGE_MAP (CMainWindow, CFrameWnd)
    ON_WM_PAINT ()
END_MESSAGE_MAP ()

下面我们一一展开这些宏:(方法很简单,就是在IDE(集成编译环境  就是编译器)中右键对应的宏,然后选择" Go To Definition Of *** " )

1. 首先展开DECLARE_MESSAGE_MAP

1)未展开的

2)展开后

2. 展开
{

BEGIN_MESSAGE_MAP (CMainWindow, CFrameWnd)
    ON_WM_PAINT ()
END_MESSAGE_MAP ()

}

1)未展开的

2)展开后

看到这里,你也许有一点儿蒙,为此,我自行绘制了一张图,它能很好的诠释消息机制的流程关系

好了,现在你应该能明白了吧,可能你还会有一个问题:

MFC本身使用c++封装的,又用一些宏来实现一个类似c++多态的消息映射机制,这不是有些多余吗?

表面上看似是这么回事儿,其实,据我了解到,当时微软的MFC的架构师们测试过,如果用c++的多态性实现,基本上每一个类的对象的储存空间要多那么几十到几百K,它们觉得这样很浪费内存,所以想出了这么一个类似于多态的消息消息映射机制

<MFC_1>深入剖析MFC的WinMain和消息机制的更多相关文章

  1. 剖析MFC六大关键技术(五六)--消息映射与命令传递

    说到消息,在MFC中,“最熟悉的神秘”可算是消息映射,那是我们刚开始接触MFC时就要面对的东西.有过SDK编程经验的朋友转到MFC编程的时候,一下子觉得什么都变了样.特别是窗口消息及对消息的处理跟以前 ...

  2. 深入剖析MFC中对于Windows消息处理、运行机制

    序: 本人对Windows系统.MFC谈不上有深入的了解,但对MFC本身包装API的机制很有兴趣,特别是读了候老师的<深入浅出MFC>后,感觉到VISUAL C++的Application ...

  3. 总结《二》MFC中WinMain和CALLBACK

    MFC中WinMain和回调函数CALLBACK 一,路线        1.一般普通窗口或控件建立调用的CWnd :: CreateEx函数        2.经过资源对话框创建的即不调用的CWnd ...

  4. MFC学习-第4课 消息机制和MFC作图

    转自: 1.http://blog.sina.com.cn/s/blog_6b5180bf01012kbz.html 2.http://blog.csdn.net/happyhhb/article/d ...

  5. WCF技术剖析之十八:消息契约(Message Contract)和基于消息契约的序列化

    原文:WCF技术剖析之十八:消息契约(Message Contract)和基于消息契约的序列化 [爱心链接:拯救一个25岁身患急性白血病的女孩[内有苏州电视台经济频道<天天山海经>为此录制 ...

  6. MFC模态对话框的消息循环

    MFC模态对话框的消息循环 单线程程序, 当主窗口响应函数中弹出模态对话框时,为什么主窗口响应函数可能照常工作? 当弹出模态对话框时,线程的消息循环无法返回,父窗口的事件本应没人处理,应该处于卡死状态 ...

  7. MFC消息机制

    何谓消息.消息处理函数.消息映射?消息简单的说就是指通过输入设备向程序发出指令要执行某个操作.具体的某个操作是你的一系列代码.称为消息处理函数. 在SDK中消息其实非常容易理解,当窗口建立后便会有一个 ...

  8. MFC原理第五讲.消息映射.以及如何添加消息

    MFC原理第五讲.消息映射.以及如何添加消息 一丶消息映射是什么 我们知道.Win32程序.都是通过消息去驱动的. 不断的在处理消息. 只要我们使用固定的宏.就可以让我们的框架知道一旦消息发生.该往哪 ...

  9. 我对windows消息机制的理解(参考深入浅出MFC,欢迎批评指正!!)

    以消息为基础,以事件驱动之 程序的进行依靠外部消息来驱动,即:程序不断等待任何可能的输入,然后做判断,然后再做适当的处理. 消息输入:操作系统捕获,以消息形式进入程序.(操作系统通过其USERS模块中 ...

随机推荐

  1. Asp.Net验证码3

    using System; using System.Collections.Generic; using System.Web; using System.Web.UI; using System. ...

  2. 设置sudo不输入密码 sudoers 编辑出错后的补救方法

    一 设置sudo为不需要密码 有时候我们只需要执行一条root权限的命令也要su到root,是不是有些不方便?这时可以用sudo代替.默认新建的用户不在sudo组,需要编辑/etc/sudoers文件 ...

  3. Java [Leetcode 96]Unique Binary Search Trees

    题目描述: Given n, how many structurally unique BST's (binary search trees) that store values 1...n? For ...

  4. linux的命令(1)

    系统信息 arch 显示机器的处理器架构(1) uname -m 显示机器的处理器架构(2) uname -r 显示正在使用的内核版本 dmidecode -q 显示硬件系统部件 - (SMBIOS ...

  5. Android Volley源码分析

    今天来顺手分析一下谷歌的volley http通信框架.首先从github上 下载volley的源码, 然后新建你自己的工程以后 选择import module 然后选择volley. 最后还需要更改 ...

  6. Informatica9.6.1在Linux Red Hat 5.8上安装遇到的有关问题整理_3

    3.Repository Service启动后的页面编码问题 1)错误信息: 2)原因分析及解决步骤 原因分析: informatica产品安装背后AdminConsole的Code page默认为U ...

  7. C#对Excel打印时,PageSetup 对象详解

    PageSetup 对象包含所有页面设置的属性(左边距.底部边距.纸张大小等).下面按“页面”.“页边距”.“页眉/页脚”.“工作表”和“无对应选项卡”五个类别,逐一介绍. 一.页面 与“页面”选项卡 ...

  8. 12、NFC技术:读写NFC标签中的Uri数据

    功能实现,如下代码所示: 读写NFC标签的Uri 主Activity import cn.read.write.uri.library.UriRecord; import android.app.Ac ...

  9. Golang 绘图基础 -绘制简单图形

    前一节讲的是 绘图到不同输出源,请看地址: http://www.cnblogs.com/ghj1976/p/3440856.html 上一节的例子效果是通过设置每一个点的的RGBA属性来实现的,这是 ...

  10. jquery小技巧汇总 持续更新中

    1.jquery高亮当前选中菜单 $("document").ready(function(){ $(".menu li").click(function(){ ...