
Window消息传递机制.docx
2页Window消息传递机制MFC 将 thread 分成 winddow thread 和 worker thread,在讨论多现程(Multi-thread)之前,我 们先只考虑window threadwindows programming的基本工作方式和console application 的不同,基本上是这样运彳亍 的,程序从WinMain()开始,然后进入一个message loop,程序在这里等待发给它的所有消 息然后一一处理,直到接收到WM_QUIT的消息的时候,message loop终止,程序结束 所以整个主程序运行的过程就是等待消息,接收消息,然后处理消息的过程窗口建立的时候CreateWindow, RegisterWindow之类的不必太费心,MFC已经全管理妥 当了,需要提起一点注意的是程序开始时HINSTANCE hInstance这个参数,在和DLL打交 道的时候会帮你解决很多问题,如果一个Bitmap Load不上来,或者一个Dialog DoModal 之后不出来,估计就得向这个参数求助了,这是后话具体处理的消息的函数叫window procedure,具体处理消息的code叫message handler0 它可以是当前应用程序的API,也可以是调用的不同DLL的API。
不同的DLL叫不同的m odule以后的文章中我会具体说明module state是个很重要的话题当项目大的时候)没有message handler的消息交给DefWindowProc()函数处理,差不多可以理解为什么也不 作了消息包括四个参数,window handle, message ID,和另外两个参数wParam, lParamwin dow 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去处理,一般的messa ge handler的接收格式是用wParam传一个关键的参数,如这次操作的具体ID,把其余的大 量辅助信息放在lParam里。
需要注意的是如果lParam传递的是一个指针(一般情况下是CO bject类的或从CObject衍生出来的),这个指针指向的变量的寿命需要足够长,因为信息Po st出去之后发送函数很可能就运行完毕了如果发送的指针是个局部变量,接收方就一定会 Crasho当然如果是发送方new出来的变量,接收方得负责帮他delete掉,这个操作很危险, 而且不一定合适有时候发送方把信息传给N个窗口,第一个窗口 delete掉了第二个窗口 就麻烦了,不delete掉又不能保证第二个窗口一定delete掉,所以如果可能,不用new为上 策用点什么成员变量,常数变量之类的比较好由于可能收到的信息种类很多,用传统的switch来处理在程序中会显得很乱,于是MFC采 用了 Message Map机制Message Map机制实现了收到的信息和处理信息函数的mappingo 在BEGIN_MESSAGE_MAP和END_MESSAGE_MAP之间定义的消息会在window接收到 之后一一传给对应的message handler处理所有用于处理信息的函数的申明需要有afx_msg关键字对于系统所要处理的message, O N_WN_XXX 一般跟三个参数,WPARAM(wParam), LOWORD(lParam)和 HIWORD(lPara m).用不到的参数会省略。
下面列举一下Message Map中可能用到的关于宏1 o Window间SendMessage或PostMessage收到的消息如果是系统将要管理的,在Message Map中一般用ON_WM_XXXXXX”是具体消息名字例如画窗口是ON_WM_PAINT如果是自定义的消息ON_MESSAGE()例如窗口 pWndA发消息给窗口 pWndBpWndB-> PostMessage(WM_MYMSG1),那么 Window B要处理这个消息需要在Message Map里面写 上 ON_MESSAGE(WM_MYMSG1, OnMessage1),然后写 OnMessage1 函数作 message han dlero WM_MYMSG1的定义应放在user message中,WM_USER+NNN注意最好不要和 其它已有的ID重复,这个没有办法自动检查2o ON_COMMAND,ON_UPDATE_COMMAND_UI,ON_COMAND_RANGEON_COMMAND只要用于menu和toolbar的点击处理,也可以用在accelerator中管理用 户的键盘输入用 ON_COMMAND 比管理 ON_WN_CHAR 好。
ON_UPDATE_COMMAND_ UI是用于更新menu或toolbar的在这个message handler里面你可以根据不同的要求ena ble或者disable当前的菜单选项或toolbar buttono ON_COMMAND_RANGE主要用于动态 的菜单的选项中当N个动态菜单选项加入时,你可以用一串连续的ID作为它们的消息管 理ID,在ON_COMMAND_RANGE定义这串ID的起始和最大值,然后响应函数就可以知 道具体是哪个动态菜单选项被选中了3o ON_COMMAND_EX,ON_COMMAND_RANGE_EX用处比较少,当多个class (CCmdTarget class)需要处理同一消息的时候,一个class如果用 ON_COMMAND_EX处理,返回TRUE,表示消息处理完毕返回FALSE则其它class可 以继续处理4o ON_REGISTERED_MESSAGE用于确认系统中新message ID唯一5o ON_CONTROL,ON_WM_XXX_REFLECT,ON_CONTROL_RANGE用于window接收其控件发来的特殊消息。
