星座邱士楷:VC消息学习总结

来源:百度文库 编辑:中财网 时间:2024/04/28 23:22:30

VC消息学习总结

分类: VC_消息 2011-07-21 14:35 37人阅读 评论(0) 收藏 举报       摘要:项目中要用到编程,由于不是计算机专业的很多从头学起,最近查了一些有关消息的内容,总结一下。主要有:消息的定义,消息的分类,消息的发送和消息的处理。

1 消息的定义

       消息系统对于一个win32程序来说十分重要,它是一个程序运行的动力源泉。一个消息,是系统定义的一个32位的值,他唯一的定义了一个事件,向Windows发出一个通知,告诉应用程序某个事情发生了。例如,单击鼠标、改变窗口尺寸、按下键盘上的一个键都会使Windows发送一个消息给应用程序。
    消息本身是作为一个记录传递给应用程序的,这个记录中包含了消息的类型以及其他信息。例如,对于单击鼠标所产生的消息来说,这个记录中包含了单击鼠标时的坐标。这个记录类型叫做MSG,MSG含有来自windows应用程序消息队列的消息信息,它在Windows中声明如下:
    typedef struct tagMsg
    {
       HWND    hwnd;       接受该消息的窗口句柄
       UINT    message;    消息常量标识符,也就是我们通常所说的消息号
       WPARAM  wParam;     32位消息的特定附加信息,确切含义依赖于消息值
       LPARAM  lParam;     32位消息的特定附加信息,确切含义依赖于消息值
       DWORD   time;       消息创建时的时间
       POINT   pt;         消息创建时的鼠标/光标在屏幕坐标系中的位置
    }MSG;、

2 消息的分类

2.1 按消息的来源分类

        按消息的来源分主要有以下3类:1)窗口消息;2)命令消息;3)控件通知消息。

       窗口消息:大概是系统中最为常见的消息,它是指由操作系统和控制其他窗口的窗口所使用的消息。例如CreateWindow、DestroyWindow和MoveWindow等都会激发窗口消息,还有我们在上面谈到的单击鼠标所产生的消息也是一种窗口消息。

        命令消息:这是一种特殊的窗口消息,他用来处理从一个窗口发送到另一个窗口的用户请求,例如按下一个按钮,他就会向主窗口发送一个命令消息。
       控件通知消息:是指这样一种消息,一个窗口内的子控件发生了一些事情,需要通知父窗口。通知消息只适用于标准的窗口控件如按钮、列表框、组合框、编辑框,以及Windows公共控件如树状视图、列表视图等。例如,单击或双击一个控件、在控件中选择部分文本、操作控件的滚动条都会产生通知消息。 她类似于命令消息,当用户与控件窗口交互时,那么控件通知消息就会从控件窗口发送到它的主窗口。但是这种消息的存在并不是为了处理用户命令,而是为了让主窗口能够改变控件,例如加载、显示数据。例如按下一个按钮,他向父窗口发送的消息也可以看作是一个控件通知消息;单击鼠标所产生的消息可以由主窗口直接处理,然后交给控件窗口处理。
    其中窗口消息及控件通知消息主要由窗口类即直接或间接由CWND类派生类处理。相对窗口消息及控件通知消息而言,命令消息的处理对象范围就广得多,它不仅可以由窗口类处理,还可以由文档类,文档模板类及应用类所处理。

2.2 按消息发送的途径分类

      按消息发送的途径可分为两类:队列消息和非队列消息。

      首先介绍一下消息队列,消息队列可以分成系统消息队列和线程消息队列。系统消息队列由Windows维护,线程消息队列则由每个GUI线程自己进行维护,为避免给non-GUI现成创建消息队列,所有线程产生时并没有消息队列,仅当线程第一次调用GDI函数数系统给线程创建一个消息队列。当鼠标、键盘事件被触发后,相应的鼠标或键盘驱动程序就会把这些事件转换成相应的消息,然后输送到系统消息队列,由Windows系统去进行处理。Windows系统则在适当的时机,从系统消息队列中取出一个消息,根据前面我们所说的MSG消息结构确定消息是要被送往那个窗口,然后把取出的消息送往创建窗口的线程的相应队列,下面的事情就该由线程消息队列操心了,Windows开始忙自己的事情去了。线程看到自己的消息队列中有消息,就从队列中取出来,通过操作系统发送到合适的窗口过程去处理。

       队列消息送到系统消息队列,然后到线程消息队列;非队列消息将会绕过系统队列和消息队列,直接将消息发送到窗口过程。

3 消息的发送

       把一个消息发送到窗口有3种方式:发送、寄送和广播。
       发送消息的函数有:SendMessage、SendMessageCallback、SendNotifyMessage、SendMessageTimeout;

       寄送消息的函数主要有:PostMessage、PostThreadMessage、PostQuitMessage;

       广播消息的函数有:BroadcastSystemMessage、BroadcastSystemMessageEx。

      SendMessage发送后,一直等到消息被处理完后才返回,而PostMessage发送后,不等消息处理立即返回。从上面的这2个具有代表性的函数,我们可以看出消息的发送方式和寄送方式的区别所在:被发送的消息是否会被立即处理,函数是否立即返回。被发送的消息会被立即处理,处理完毕后函数才会返回;被寄送的消息不会被立即处理,他被放到一个先进先出的队列中,一直等到应用程序空线的时候才会被处理,不过函数放置消息后立即返回。

4 消息处理过程 

      1.AfxWndProc()接收消息,寻找消息所属的CWnd对象,然后调用AfxCallWndProc( )。

      2.AfxCallWndProc()存储消息(消息标识符和消息参数)供未来参考,然后调用WindowProc( )。

      3.WindowProc()发送消息给OnWndMsg( ),如果消息未被处理,则发送给DefWindowproc( )。

      4.OnWndMsg()首先按字节对消息进行排序,对于WM_COMMAND消息,调用OnCommand()消息响应函数;对于WM_NOTIFY消息调用OnNotify()消息响应函数。任何被遗漏的消息将是标准消息。OnWndMsg()函数搜索类的消息映像,以找到一个能处理任何窗口消息的处理函数。如果OnWndMsg()函数不能找到这样的处理函数的话,则把消息返回到WindowProc()函数,由它将消息发送给DefWindowProc()函数。

      5.OnCommand()查看这是不是一个控件通知(lParam参数不为NULL),如果它是,OnCommand()函数会试图将消息映射到制造通知的控件;如果它不是一个控件通知,或者控件拒绝映射的消息,OnCommand()就会调用OnCmdMsg()函数。

      6.OnNotify( )也试图将消息映射到制造通知的控件;如果映射不成功,OnNotify( )就调用相同的OnCmdMsg( )函数。

        7.根据接收消息的类,OnCmdMsg()函数将在一个称为命令传递(Command Routing)的过程中潜在的传递命令消息和控件通知。例如:如果拥有该窗口的类是一个框架类,则命令和控件通知消息也被传递到视图和文档类,并为该类寻找一个消息处理函数。

      MFC消息控制流最具特色的地方是CWnd类的虚拟函数PreTranslateMessage(),通过重载这个函数,可以改变MFC的消息控制流程,甚至可以作一个全新的控制流出来。只有穿过消息队列的消息才受PreTranslateMessage()影响,采用SendMessage()或其他类似的方式向窗口直接发送的而不经过消息队列的消息根本不会理睬PreTranslateMessage()的存在。

        MFC 中PreTranslateMessage是GetMessage(...)函数的下一级操作,即GetMessage(...)从消息队列中获取消息后,交由PreTranslateMessage()处理,若其返回FALSE则再交给TranslateMessage  和 DispatchMessage处理(进入WindowProc);
如果用SendMessage,   则消息直接交到WindowProc处理,所以GetMessage不会取得SendMessage的消息,当然PreTranslateMessage也就不会被调用。