标题:[原创]Window消息传递机制
只看楼主
myajax95
Rank: 16Rank: 16Rank: 16Rank: 16
等 级:版主
威 望:30
帖 子:2978
专家分:0
注 册:2006-3-5
 问题点数:0 回复次数:4 
[原创]Window消息传递机制


MFC将thread分成winddow thread和worker thread,在讨论多现程(Multi-thread)之前,我们先只考虑window thread。

windows programming的基本工作方式和console application的不同,基本上是这样运行的,程序从WinMain()开始,然后进入一个message loop,程序在这里等待发给它的所有消息然后一一处理,直到接收到WM_QUIT的消息的时候,message loop终止,程序结束。所以整个主程序运行的过程就是等待消息,接收消息,然后处理消息的过程。

窗口建立的时候CreateWindow, RegisterWindow之类的不必太费心,MFC已经全管理妥当了,需要提起一点注意的是程序开始时HINSTANCE hInstance这个参数,在和DLL打交道的时候会帮你解决很多问题,如果一个Bitmap Load不上来,或者一个Dialog DoModal之后不出来,估计就得向这个参数求助了,这是后话。

具体处理的消息的函数叫window procedure,具体处理消息的code叫message handler。它可以是当前应用程序的API,也可以是调用的不同DLL的API。不同的DLL叫不同的module。以后的文章中我会具体说明module state。是个很重要的话题。(当项目大的时候)

没有message handler的消息交给DefWindowProc()函数处理,差不多可以理解为什么也不作了。

消息包括四个参数,window handle,message ID,和另外两个参数wParam, lParam。window handle可以作为window的识别ID来用。所以在发送消息的时候如果可以有两种格式:
CWnd *pWnd = ....
if (pWnd && pWnd->GetSafeWnd())

pWnd->SendMessage(message, wParam = 0, lParam);
或者
SendMessage(pWnd->GetSafeWnd(), message, wParam, lParam )

发送消息如果用SendMessage消息将立刻发送,如果用PostMessage,消息将进入Message queue按当前顺序发送,一般没有特别的要求PostMessage已经足够了。
处理消息的时候根据不同的Message ID交给不同的message handler去处理,一般的message handler的接收格式是用wParam传一个关键的参数,如这次操作的具体ID,把其余的大量辅助信息放在lParam里。需要注意的是如果lParam传递的是一个指针(一般情况下是CObject类的或从CObject衍生出来的),这个指针指向的变量的寿命需要足够长,因为信息Post出去之后发送函数很可能就运行完毕了。如果发送的指针是个局部变量,接收方就一定会Crash。当然如果是发送方new出来的变量,接收方得负责帮他delete掉,这个操作很危险,而且不一定合适。有时候发送方把信息传给N个窗口,第一个窗口delete掉了第二个窗口就麻烦了,不delete掉又不能保证第二个窗口一定delete掉,所以如果可能,不用new为上策。用点什么成员变量,常数变量之类的比较好。

由于可能收到的信息种类很多,用传统的switch来处理在程序中会显得很乱,于是MFC采用了Message Map机制。Message Map 机制实现了收到的信息和处理信息函数的mapping。在BEGIN_MESSAGE_MAP和END_MESSAGE_MAP之间定义的消息会在window接收到之后一一传给对应的message handler处理。

所有用于处理信息的函数的申明需要有afx_msg关键字。对于系统所要处理的message,ON_WN_XXX 一般跟三个参数,WPARAM(wParam),LOWORD(lParam) 和HIWORD(lParam).用不到的参数会省略。

下面列举一下Message Map中可能用到的关于宏

1。Window间SendMessage或PostMessage收到的消息如果是系统将要管理的,在Message Map中一般用ON_WM_XXX。“XXX”是具体消息名字。例如画窗口是ON_WM_PAINT。如果是自定义的消息ON_MESSAGE()。例如窗口pWndA发消息给窗口pWndB。pWndB->PostMessage(WM_MYMSG1),那么Window B要处理这个消息需要在Message Map里面写上 ON_MESSAGE(WM_MYMSG1, OnMessage1),然后写OnMessage1函数作message handler。WM_MYMSG1的定义应放在user message中,WM_USER+NNN。注意最好不要和其它已有的ID重复,这个没有办法自动检查。

2。ON_COMMAND,ON_UPDATE_COMMAND_UI,ON_COMAND_RANGE
ON_COMMAND只要用于menu和toolbar的点击处理,也可以用在accelerator中。管理用户的键盘输入用ON_COMMAND比管理ON_WN_CHAR好。ON_UPDATE_COMMAND_UI是用于更新menu或toolbar的。在这个message handler里面你可以根据不同的要求enable或者disable当前的菜单选项或toolbar button。ON_COMMAND_RANGE主要用于动态的菜单的选项中。当N个动态菜单选项加入时,你可以用一串连续的ID作为它们的消息管理ID,在ON_COMMAND_RANGE定义这串ID的起始和最大值,然后响应函数就可以知道具体是哪个动态菜单选项被选中了。

3。ON_COMMAND_EX,ON_COMMAND_RANGE_EX
用处比较少,当多个class (CCmdTarget class)需要处理同一消息的时候,一个class如果用ON_COMMAND_EX处理,返回TRUE,表示消息处理完毕。返回FALSE则其它class可以继续处理。

4。ON_REGISTERED_MESSAGE
用于确认系统中新message ID唯一。

5。ON_CONTROL,ON_WM_XXX_REFLECT,ON_CONTROL_RANGE
用于window接收其控件发来的特殊消息。

以后将附一个包含所有宏的小例子。

搜索更多相关主题的帖子: Window windows thread 机制 loop 
2006-08-07 05:06
aogun
Rank: 5Rank: 5
等 级:贵宾
威 望:17
帖 子:638
专家分:0
注 册:2006-4-5
得分:0 

呃,支持原创,我比较懒,呵呵,对于ajax能动手写这么多东西还是蛮欣赏的


世界上总共有 10 种人,一种懂得什么是二进制 ,一种不懂。
2006-08-07 14:19
myajax95
Rank: 16Rank: 16Rank: 16Rank: 16
等 级:版主
威 望:30
帖 子:2978
专家分:0
注 册:2006-3-5
得分:0 
写的都是刚学的不全会的,所以大家帮忙看看有没有问题。对ON_CONTROL,ON_WM_XXX_REFLECT,ON_CONTROL_RANGE还没全高清楚,回头更新一下。

http://myajax95./
2006-08-07 14:23
woodhead
Rank: 3Rank: 3
等 级:新手上路
威 望:9
帖 子:1124
专家分:0
注 册:2005-7-18
得分:0 
message based event driven
看书意思容易明白,但要写起来就晕菜了。

2006-08-07 18:33
kuangcf
Rank: 1
等 级:新手上路
帖 子:2
专家分:0
注 册:2011-12-16
得分:0 
ok!
2011-12-16 15:49



参与讨论请移步原网站贴子:https://bbs.bccn.net/thread-82498-1-1.html




关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 1.107755 second(s), 7 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved