Windows 应用程序交互过程

应用程序

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

但是一般来说不是所有的消息都是需要程序处理的.而是针对其中某些特定的消息进行处理.即程序只关心自己想关心的问题而不会多去处理其他不必要的信息.但是系统并不会知道什么是程序所关心的消息,什么是程序不关心的消息,所以它会把所有的消息都发送给程序.那么程序便要从中塞选出自己想要处理的消息,然后把自己不想理会的消息过滤给系统,让系统去帮助处理这些不需要的消息(即系统提供的默认的窗口过程函数 DefWindowProc).那么一般程序的窗体过程具体流程如下:

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

消息

  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 };
    复制代码

  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 结构体设计窗体基本属性是定义的),通过窗口回调函数来处理消息,处理消息结束后,应用回调函数把权限在交还给系统然后,系统在执行权限交给应用程序.程序继续从消息队列中取出消息并按上述方法去处理消息之.流程如下:

总有一个信仰让我们为之奋斗终生。

6 声望
0 粉丝
0 条评论
推荐阅读
字符编码笔记:ASCII,Unicode 和 UTF-8
我们知道,计算机内部,所有信息最终都是一个二进制值。每一个二进制位(bit)有0和1两种状态,因此八个二进制位就可以组合出256种状态,这被称为一个字节(byte)。也就是说,一个字节一共可以用来表示256种不同...

逐梦星空阅读 2.3k

VBS 入门交互实战
VBS 是一种 Windows 脚本语言,全称是 Microsoft Visual Basic Script Editon,微软公司可视化 BASIC 脚本版

tiny极客2阅读 828评论 3

封面图
一行命令切换win11的右键菜单,改为win10风格
问题:升级到Win11后不喜欢新的右键菜单,因为需要两次击才能显示更多选项。网上找了一堆乱七八糟的办法,大部分都不能用:修改注册表用脚本修改注册表安装修改菜单的软件(太麻烦)这里介绍一种简单粗暴的,修改...

luckybo1阅读 743

解决宏碁非凡S3 安装Win11时无法找到驱动器问题
1 问题描述机型:宏碁非凡S3 2022款CPU:i5 1240P安装系统:Win11 专业版问题描述:安装系统时,在选择驱动器界面无法找到驱动器,如下图所示2 解决流程查了一下网上的解决办法,进入BIOS把VMD Controller关闭掉...

xcghvgshjdfghsd阅读 1.1k

@WSL2 从零开始配置WSL2
WSL全称Windows Subsystem for Linux,官方翻译“适用于Linux的Windows子系统”(个人觉得翻译成Windows的Linux子系统更符合国人语言习惯)。以下是微软官方对WSL的描述

Blueye阅读 1.1k

使用 Winget 命令在 Windows 上安装软件
Winget 是微软推出的一款安装包管理工具,使用户能够在命令行下寻找、安装、升级、删除和配置应用程序。这里以安装焰火十二卷(Rickrack)为例,演示了 Winget 的使用流程。

本征喵函数阅读 1k

封面图
【Ubuntu】Win11 VmWare虚拟机安装Ubuntu 22.04.1-server
引言如标题所说,属于个人虚拟机安装Ubuntu的笔记记录。VM安装网络上有很多教程,这里就直接省略了。下载Ubuntu 22.04.1-server进入Ubuntu的中文网站:Ubuntu系统下载 | Ubuntu根据最新的版本下载即可。本次使用...

Xander阅读 977

总有一个信仰让我们为之奋斗终生。

6 声望
0 粉丝
宣传栏