Windows 应用程序交互过程

应用程序

Windows的应用程序通常包含窗口(Window),它主要为用户提供一种可视化的交互方式(窗口是由线程(Thread)建立的).Windows 系统经过消息机制来让系统和用户进行交互,用户经过触发事件来触发消息,消息(Message)被发送,保存,处理,一个线程会维护本身的一套消息队列(Message Queue)[仅当线程有对应的建立窗口和处理窗口消息时候],在发生输入事件以后,Windows 系统将事件转换为一个消息并将消息放入程序的消息队列中.程序经过执行一块称之为「消息循环」的程序代码从消息队列中取出消息并调用窗体的回调函数处理消息,这样不只保持线程间的独占性.并且队列的以先进先出方式处理消息来实现异步通讯.windows

可是通常来讲不是全部的消息都是须要程序处理的.而是针对其中某些特定的消息进行处理.即程序只关心本身想关心的问题而不会多去处理其余没必要要的信息.可是系统并不会知道什么是程序所关心的消息,什么是程序不关心的消息,因此它会把全部的消息都发送给程序.那么程序便要从中塞选出本身想要处理的消息,而后把本身不想理会的消息过滤给系统,让系统去帮助处理这些不须要的消息(即系统提供的默认的窗口过程函数 DefWindowProc).那么通常程序的窗体过程具体流程以下:异步

上面能够看出窗体能够接收和处理消息的特性.然而控件其实也都是窗口.可是每一个控件却不必定都具备接收和处理消息的功能.由于在系统中只有具备句柄(一个系统自动维护的32位的数值,是做为系统对象的简单的惟一性的标识)的窗口才具备处理消息的特性.由于只有具备句柄的窗口才能独立存在做为一窗体存在.做为其余控件的容器.而没有句柄的控件,如Label,是不能独立存在的,只能做为窗口控件的子控件,它不能绘制自身,只能依靠父窗体将它绘制来.ide

消息

  1. 消息载体

    消息由一个叫MSG的结构体定义,包括窗口句柄(HWND),消息ID(UINT),参数(WPARAM, LPARAM)等等:函数

    复制代码
    1 struct MSG
    2 {
    3 HWND hwnd;
    4 UINT message;
    5 WPARAM wParam;
    6 LPARAM lParam;
    7 DWORD time;
    8 POINT pt;
    9 };
    复制代码spa

  2. 消息的简单分类

    通常来讲消息可以被分为「队列化的」和「非队列化的」.操作系统

    • 队列化的消息是由Windows放入程序消息队列中的.在程序的消息循环中,从新传回并分配给窗口消息处理程序.即把消息发送给程序的消息队列中,等带消息处理函数取出并处理消息.队列化消息基本上是使用者输入的结果,以击键(如WM_KEYDOWN和WM_KEYUP消息)、击键产生的字符(WM_CHAR)、鼠标移动(WM_MOUSEMOVE)和鼠标按钮(WM_LBUTTONDOWN)的形式给出.队列化消息还包含时钟消息(WM_TIMER)、更新消息(WM_PAINT)和退出消息(WM_QUIT).
    • 非队列化的消息在Windows呼叫窗口时直接送给窗口消息处理程序.直接进行消息处理.非队列化消息则是其它消息.在许多状况下,非队列化消息来自呼叫特定的Windows函数.例如,当WinMain呼叫CreateWindow时,Windows将创建窗口并在处理中给窗口消息处理程序发送一个WM_CREATE消息.当WinMain呼叫ShowWindow时,Windows将给窗口消息处理程序发送WM_SIZE和WM_SHOWWINDOW消息.当WinMain呼叫UpdateWindow时,Windows将给窗口消息处理程序发送WM_PAINT消息.
    • 注意: 键盘或鼠标输入时发出的队列化消息信号,也能在非队列化消息中出现.例如,用键盘或鼠标选择了一个菜单项时,键盘或鼠标消息就是队列化的,而说明菜单项已选中的WM_COMMAND消息则可能就是非队列化的.
    • 任何状况下,窗口消息处理程序都将得到窗口全部的消息--包括队列化的和非队列化的
  3. 消息队列

    1. 系统队列线程

      当操做系统启动并初始化时,线程Raw Input Thread(RIT)就会启动,并创系统硬件输入队列(System Hardware Input Queue)(SHIQ). 对于外部的硬件事件(鼠标或者键盘),硬件驱动会将事件转换成消息,并存放到SHIQ中,而RIT线程就专门负责处理SHIQ中的消息,把消息分发到对应线程的消息队列里面.
    2. 线程队列翻译

      而对于线程来讲,每一个线程能够拥有本身的消息队列,它和线程一一对应.在线程刚建立时,消息队列并不会被建立,而是当GDI的函数调用发生时,Windows系统才认为有必要为线程建立消息队列.系统会为其维护一个THREADINFO结构.  
      消息队列包含在一个叫THREADINFO的结构中,有四个队列:
      
      *   Sent Message Queue 发送消息队列 \[该队列保存其余程序经过SendMessage给该线程发送的消息\]
      *   Posted Message Queue 登记消息队列 \[该队列保存其余队列经过PostMessage给该线程发送的消息\]
      *   Visualized Input Queue 输入消息队列 \[保存系统队列分发过来的消息,好比鼠标或者键盘的消息\]
      *   Reply Message Queue 响应消息队列 \[保存向窗体发送消息后的结果,好比sendMessage操做结束后,接收消息方会发送一个Reply消息给发送方的Reply队列中,以唤醒发送队列\]
THREADINFO结构体定义以下图所示:

消息管理机制

  1. 消息源

     消息能够由Windows系统发送,也能够由应用程序自己;能够向线程内发送,也能够跨线程.主要是看发送函数的调用者.设计

  2. 附加参数:

    系统向窗口发送的消息一般包含3个参数,分别是:指针

    • 窗口句柄(a window handle):窗口句柄用来标识消息将要发送到的窗口对象,系统使用窗口句柄来肯定哪个窗口句柄应该接收该消息.
    • 消息标识符(a message identifier):消息标识符是用来区分不一样消息的命名常量,当窗口过程接收到一个消息时,它使用消息标识符来肯定如何处理该消息.例如,消息标识符WM_PAINT告诉窗口过程“窗口的客户区已经发生变化,窗口必须进行从新绘制”.
    • 消息参数(message parameters):消息参数用来表述窗口过程处理消息时所使用的数据或数据的位置,一般用一对参数表示(即2个长整型的参数:WPARAM, LPARAM).消息参数的意义和取值取决于消息.当不须要使用消息参数时,一般将其设置为NULL.窗口过程必须经过检查消息标识符来肯定如何对消息参数进行解释.
  3. 传递过程:

    用户在操做程序时对电脑的操做这个事件将会被系统捕获到,而后把这个事件翻译成一个消息而且把消息投递到对应的消息队列中.而程序发现本身的消息队列中具备消息时它便会从本身的消息队列中取出消息并处理消息.直至消息队列为空为止.

  4. 三级结构

    Windows消息控制中心通常是三层结构,其顶端就是Windows内核.Windows内核维护着一个消息队列,第二级控制中心从这个消息队列中获取属于本身管辖的消息,后作出处理,有些消息直接处理掉,有些还要发送给下一级窗体(Window)或控件(Control).第二级控制中心通常是各Windows应用程序的Application对象.第三级控制中心就是Windows窗体对象,每个窗体都有一个默认的窗体过程,这个过程负责处理各类接收到的消息.

总结

首先咱们要了解 windows 系统下程序是以消息为基础,事件驱动之.首先用户出发事件,而后系统把事件转换为对应的消息,而后把消息投递到消息队列中.应用程序经过消息循环得到消息,而后把消息转交个系统,有系统再把消息交给对应的窗口回调函数(系统经过以注册的窗口类结构中的一个指向回调函数指针的成员找到窗体的回调函数,而这个窗体结构体是在窗体建立过程当中设计窗体类时候经过定义一个 WNDCLASS 结构体设计窗体基本属性是定义的),经过窗口回调函数来处理消息,处理消息结束后,应用回调函数把权限在交还给系统而后,系统在执行权限交给应用程序.程序继续从消息队列中取出消息并按上述方法去处理消息之.流程以下:

相关文章
相关标签/搜索