首先看下事件和消息的区别,refer to http://topic.csdn.net/t/20021015/16/1099048.html
引用侯捷的话就是“以讯息为基础,以事件驱动之(message based, event driven)”。Windows程序的进行依靠外部发生的事件来驱动。事件发生后(例如按下一个键),最终转化为消息,放入消息队列。程序从消息队列取得消息并处理。这就是Windows程序。
http://www.mianwww.com/html/2012/04/15213.html
Windows为当前执行的每个Windows程序维护一个「消息队列」。在发生输入事件之后,Windows将事件转换为一个「消息」并将消息放入程序的消息队列中。程序通过执行一块称之为「消息循环」的程序代码从消息队列中取出消息:
while(GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
TranslateMessage(&msg);将msg结构传给Windows,进行一些键盘转换。
DispatchMessage (&msg);又将msg结构回传给Windows。然后,Windows将该消息发送给适当的窗口消息处理程序,让它进行处理。
SendMessage()与PostMessage()之间的区别是什么?
它们两者是用于向应用程序发送消息的。PostMessagex()将消息直接加入到应用程序的消息队列中,不等程序返回就退出;而SendMessage()则刚好相反,应用程序处理完此消息后,它才返回。
******************************************
MFC消息映射机制
http://hi.baidu.com/gcc_sky/item/4f6ca4afd6a3b328030a4dad
在讲述消息循环时,曾介绍过,当有消息产生时,操作系统会把这条消息放到应用程序的消息队列中,应用程序通过GetMessage函数从这个队列中取出一条具体的消息,并通过DispatchMessage函数把消息交给操作系统,后者调用应用程序的窗口过程即窗口过程函数WndProc进行处理。该函数利用switch-case结构对消息进行判别并分类处理。然而,我们看到在MFC程序中,并不是按照这种途径进行处理的,只要遵照上述步骤,定义了与消息有关的三处信息后,就可以实现了消息的相应处理。MFC中采用的这种消息处理机制成为MFC消息处理机制。
实际上,消息路由可以有多种实现方式。其中一种可能的实现方式是,在基类中针对每种消息定义一个虚函数。当子类需要对某个消息进行处理时,只需要重写基类相应的虚函数即可。当在程序中调用这个函数时,根据多态性原理,如果子类重写了该函数,就调用子类的这个函数,否则就调用父类的响应函数。通过这种方式也可以完成消息的路由。这样做在原理上讲是没有问题的,但是从编程角度讲,是不可取的。
为什么不可取?因为虚函数必须由一个虚函数表(vtable)来实现。在应用程序中使用的每个派生类,系统都要为他们分配一个vtable,并且不管基类中虚函数是否确实在派生类中被重写,这个vtable表中都要为基类的每一个虚函数提供一个4字节的输入项。而我们知道,MFC中类的派生层次很多,这样做,将使MFC类及其派生类背着一个很大的虚拟函数表的包袱,这对内存资源是一种浪费。而且,每次扫描虚拟函数表也是非常萧寒时间的操作,这种定义虚拟函数的做法显然是不合适的。所以,MFC没有采用虚拟函数这种机制,而是采用一种称之为消息映射的机制来完成消息路由。
MFC消息映射机制的具体实现方法是:在每个能接收和处理消息的类中,定义一个消息和消息函数静态对照表,即消息映射表。在消息映射表中,消息与对应的消息处理函数指针是成对出现的。某个类能处理的所有消息及其对应的消息处理函数的地址都列在这个类所对应的静态表中。当有消息需要处理时,程序只要搜索改消息静态表,查看表中是否含有该消息,就可知道该类能否处理此消息。如果能处理该消息,则同样依照静态表能很容易找到并调用对应的消息处理函数。
******************************************
http://sunxin1001.iteye.com/blog/919434
******************************************
使用 虚函数表和消息映射表 来实现消息利弊的讨论
http://topic.csdn.net/u/20090822/16/4cf5d189-0e5e-41ff-9ba3-c7eaf2f6da74.html?seed=811474963&r=79060872#r_79060872
delphi是使用虚函数来实现消息映射的
******************************************
每个类都有一个虚函数表,每个类(合适的)也都有一个消息映射表
调用类对象的一个虚函数时-----或者自己直接call或者操作系统调用,从本类的虚函数表中查找到此虚函数的地址,然后调用。子类的虚函数表完全从父类复制过来,然后如果子类有重载某个虚函数,就在子类虚函数表的相应函数指针位置修改函数指针,使其指向子类重载过的虚函数。这样子类调用道德虚函数就是子类重载过的虚函数了。见深入浅出p68。而在vc的子类的虚函数中很多都会再去调用父类的对应虚函数。
调用类对象的一个消息处理函数时-----或者自己直接call或者自己sendmessage到应用程序消息队列,或者本程序的ui的某个事件触发这个了消息然后然后由mfc sendmessage到应用程序消息队列,或者由操作系统捕获到某个事件(比如关机,调节音量)然后又os sendmessage到程序的系统消息队列等,从本类的消息映射表中查找是否有处理该消息的消息处理函数,如果没有,再去父类的消息映射表中寻找,知道找到,如果找不到,到默认的消息处理函数中。
。而在vc的子类的消息处理函数中很多都会再去调用父类的对应消息处理函数。
看来消息映射表是牺牲了cpu性能(消息对应的处理函数的寻找需要占用cpu)而节省了内存(子类不必记录父类所有的消息映射记录,只需记录新的消息记录和需要捕获--重载的消息记录)。而虚函数表则牺牲了内存(每个子类都有一个父类的虚函数表的拷贝)而节省了cpu(由于子类有父类虚函数表的拷贝,所以寻找对应的虚函数时,只在子类的虚函数表中寻找即可,而不必去父类的虚函数表中寻找)
另外每个类对象都会有一个指针成员变量:指向类的虚函数表。这样对象就会很容易找到某个虚函数。但是没有一个指针成员指向消息映射表,那么怎么找到消息映射表的呢。mfc使用了DECLARE_MESSAGE_MAP,内含getmessagemap()可以找到消息映射表。
消息处理函数和虚函数有异曲同工之处,使用虚函数开实现消息映射应该更简明。mfc抛弃c++现成的虚函数机制不用,而使用那些晦涩的宏来为每个类建立一个消息映射表从而建立一个消息映射网络使得消息可以从子类流向父类,觉得在现在很不明智。或许mfc还因为那个doc/view的消息流向不单单是子类到父类的原因才使用了消息映射表,,,,但是使用虚函数表同样也可以建立那种复杂的消息流向啊。