新书推荐:2.3 消息机制

2024-06-10 12:52
文章标签 推荐 消息 机制 2.3 新书

本文主要是介绍新书推荐:2.3 消息机制,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Windows程序的消息机制是指在Windows操作系统下,应用程序与操作系统之间的一种通信方式。通过消息机制,应用程序可以接收来自操作系统的各种事件和请求,以便做出相应的响应和处理。

在Windows程序中,消息机制的实现是基于消息队列和消息循环的。消息队列是一个用于存储消息的缓冲区,当操作系统有消息需要传递给应用程序时,消息会被放入消息队列中。消息循环是应用程序的主循环,在消息循环的过程中,应用程序从消息队列中取出消息并进行处理。

Windows程序中的各种事件和请求都经过消息机制进行传递,比如鼠标点击、键盘输入、窗口尺寸改变等等。当发生这些事件时,操作系统会将相应的消息放入消息队列中,并通知应用程序有新的消息到达。应用程序在消息循环中不断地检查消息队列,处理队列中的消息,直到队列为空或者收到退出消息。

应用程序可以通过消息处理函数来响应不同类型的消息。当该类型的消息到达时,消息处理函数就会被调用,可以在该函数中编写相应的逻辑来处理消息。消息处理函数可以是在创建窗口时指定的窗口过程函数,或者是通过注册消息回调函数的方式来实现。绝大多数消息都是由Windwos系统默认的窗口过程来处理的。

本节必须掌握的知识点:

        消息队列

        消息循环

2.3.1 消息队列

       Windows程序中的消息队列是属于线程的。每个线程初始化时都可以创建一个线程所属的消息队列。但通常在Windows程序中,只有负责处理窗口消息的主线程创建消息队列,因此,我们将线程消息队列也称之为窗口消息队列。通常Windows程序将与用户交互的消息送入消息队列进行同步。例如鼠标消息、键盘消息、绘图消息等。

       此外,一些不需要同步的消息会直接分发给窗口过程进行处理,不进入消息队列。

       ■Windows系统消息队列

       Windows操作系统是多任务系统,通常同时有多个窗口程序在运行。所有进程的消息都会被送入Windows系统内的总消息队列。然后再将总消息队列中的消息按照所属的窗口分发给每个进程的窗口消息队列。这就需要判断消息应该属于哪个窗口。

在Windows程序中,消息是通过窗口句柄来进行分发和处理的。每个窗口都有一个唯一的窗口句柄(HWND),它用于标识和引用该窗口。通过窗口句柄,可以将收到的消息正确地分发给相应的窗口。

当Windows操作系统产生一个消息并将其放入消息队列时,消息中会包含目标窗口的句柄。然后,在应用程序的消息循环中,通过处理该消息的程序会根据消息中的窗口句柄,将消息分发给对应的窗口进行处理。

在处理消息的过程中,应用程序可以使用窗口句柄来识别消息应该属于哪个窗口。通常,在处理消息的代码中,可以使用如下方式来判断消息属于哪个窗口:

●检查消息中的窗口句柄与已创建的窗口句柄是否匹配。这可以通过保存窗口句柄的变量或数据结构来完成,然后将收到的消息中的窗口句柄与保存的窗口句柄进行比较。

●使用GetWindowLongPtr函数或GetWindowLong函数获取窗口的扩展信息(例如窗口的额外数据)。可以根据扩展信息中的标识或其他自定义数据来判断消息是属于哪个窗口。

●使用其它窗口属性或特征来判断。(例如窗口类名、窗口标题等)。

    问题似乎回到了原点,最初消息被Windows操作系统捕获时就应该确定其属于哪个窗口。我们分类来讨论。

       1.如果是鼠标消息,Windows系统会根据鼠标消息的坐标位置来确定它所处的位置属于哪个窗口。当然也有另外一种情况,就是一个窗口会主动捕获并拥有一个鼠标消息。

       2.如果是键盘消息,那么该键盘消息一定是属于当前处于焦点状态的窗口,即当前拥有键盘输入焦点的窗口。如果要想改变键盘消息所属的窗口,只能是切换焦点窗口。

       3.如果是子窗口控件、菜单、快捷键消息,其本身就属于指定的窗口,毋庸置疑。

       ■窗口消息队列

窗口消息队列是Windows操作系统中负责存储消息的一个缓冲区。每个线程都有自己的消息队列,用于接收和存储操作系统发送给应用程序的消息。在Windows程序中,消息队列起到了重要的作用,用于传递各种事件和请求,例如键盘输入、鼠标点击、窗口尺寸改变等。

消息队列是一个先进先出(FIFO)的数据结构,新的消息会被添加到队列的尾部,而从队列头部会取出最早进入队列的消息。当操作系统接收到一个消息时,会将该消息放入相应线程的消息队列中,然后通知该线程有新消息到达。

2.3.2 消息循环

应用程序可以通过消息循环来检查和处理消息队列中的消息。在消息循环中,应用程序会不断地从消息队列中取出消息进行处理,直到队列为空或者收到退出消息。

一般来说,消息循环具有以下形式:

while (GetMessage(&msg, NULL, 0, 0))

{

    TranslateMessage(&msg);

    DispatchMessage(&msg);

}

在这个消息循环中,GetMessage函数会从消息队列中取出一条消息,并将其存储在 msg 变量中。

键盘消息

如果是键盘按键消息,TranslateMessage函数会将虚拟键消息翻译为字符消息。它会检查消息的类型,如果是某些特殊键(如功能键、方向键等),则生成一个 WM_KEYDOWN 或 WM_KEYUP 消息;如果是一个字符键消息,则生成一个 WM_CHAR 消息。TranslateMessage 的作用是为了在键盘输入时生成合适的字符消息。接着将WM_CHAR 消息重新送入消息队列。

其他消息

其他消息则直接由DispatchMessage 函数将消息分发到相应的窗口过程函数进行处理。它会根据消息中的窗口句柄找到对应的窗口过程函数,并将消息传递给它。窗口过程函数负责处理具体的消息,它会根据消息类型和需要执行相应的逻辑,比如绘图、更新窗口状态、响应用户输入等。

总结一下,窗口消息队列是用于存储消息的缓冲区,当操作系统有消息需要传递给应用程序时,会将消息放入消息队列中。应用程序在消息循环中检查消息队列,从中取出消息并将其发送给相应的窗口过程函数进行处理。这样,应用程序能够接收并响应用户输入和操作系统事件。

在Windows程序中,如果是由我们主动发送消息呢?则需要调用下面两个函数。

●PostMessage函数:

PostMessage是一个Windows API函数,用于将一个消息放入与指定窗口关联的线程的消息队列中,等待线程处理。此消息并不会直接发送到窗口过程函数,而是立即返回,消息的处理可能会在稍后才进行。

以下是PostMessage函数的原型:

BOOL PostMessage(

  HWND   hWnd,      // 窗口句柄

  UINT   Msg,           // 消息

  WPARAM wParam,   // 额外的消息相关信息

  LPARAM lParam        // 额外的消息相关信息

);

参数含义:

hWnd:接收消息的窗口句柄。这可以是具体的窗口句柄,也可以是一些特殊值,如HWND_BROADCAST(指所有窗口)。如果此参数为NULL,则消息会发送给调用线程的消息队列。

Msg:需要发送的消息码,如WM_CLOSE。

wParam,lParam:与消息有关的额外信息。

PostMessage函数将消息投递到消息队列后就会立即返回,不管消息是否被目标窗口过程函数处理。也就是说PostMessage是异步的,主要用于在不要求立即处理消息的情况下通知其他窗口一个事件发生,比如通知其他窗口更新显示内容。

如果你希望立即发送并处理消息,应该使用SendMessage函数。不同于PostMessage,SendMessage会立即触发窗口的窗口过程函数处理消息,并等待处理完毕后返回。

●SendMessage函数:

SendMessage是一个Windows API函数,用于将一个消息发送到指定的窗口,并等待接收消息的窗口处理完该消息后返回。这个函数与PostMessage的最大区别就是:SendMessage是同步的,消息会立即被处理,而不是被投递到消息队列中等待处理。

以下是SendMessage函数的原型:

LRESULT SendMessage(

  HWND   hWnd,      // 窗口句柄

  UINT   Msg,           // 消息

  WPARAM wParam,     // 额外的消息相关信息

  LPARAM lParam        // 额外的消息相关信息

);

参数含义:

hWnd:接收消息的窗口句柄。这可以是具体的窗口句柄,也可以是一些特殊值。

Msg:需要发送的消息码,如WM_CLOSE。

wParam,lParam:与消息有关的额外信息。

SendMessage函数会立即调用目标窗口的窗口过程,传递给它消息码和额外信息,等待窗口过程处理完消息后再返回。这意味着在消息处理完成前,SendMessage函数会一直被阻塞。

请注意,对于可能会导致长时间等待的操作(如网络操作或大量计算),不应使用SendMessage进行处理,因为这可能造成应用程序的阻塞。此时,应使用PostMessage进行异步操作,或者设计一种将这种操作异步化的机制。

       ■窗口程序运行过程

       如图2-10所示,我们把Windows程序分为4个部分:Windows操作系统、主程序、窗口过程、其他应用程序。

       ●主程序我们已经非常熟悉了,分为五个固定的步骤,主程序的核心是一个消息循环,调用GetMessage函数不间断的从窗口消息队列获取消息。

       ●窗口过程负责处理消息,switch结构不处理的消息都交给DefWindProc默认窗口过程处理,处理后返回Windows系统。

       ●Windows操作存在一个总的消息队列和各个不同进程的窗口消息队列。Windows系统负责捕获消息或产生消息。如果是鼠标键盘消息则送入消息队列,非队列消息直接传递给窗口过程处理。Windows系统中的USER32.dll负责处理窗口界面处理。

       ●其他应用程序也可能向本进程发送消息。如果调用PostMessage函数向指定窗口过程发送消息,该消息将被分发到本进程的窗口消息队列。如果调用的是SendMessage函数发送的消息,则该消息会被直接发送给指定的窗口过程处理。

             

图2-10  窗口程序运行过程

举例

       一个完整的消息传递过程:

       第一步:Windows操作系统捕获键盘消息WM_KEYDOWN,并将该消息送入操作系统总消息队列。

       第二步:Windows系统将键盘消息分发给当前焦点窗口的窗口消息队列。

       第三步:主程序的消息循环GetMessage函数从消息队列中获取键盘消息。

       第四步:TranslateMessage函数将WM_KEYDOWN消息转换为WM_CHAR消息,并将WM_CHAR消息重新送入消息队列。

       第五步:DispatchMessage函数将WM_CHAR消息分发给Windows系统。

       第六步:Windows系统将WM_CHAR消息传递给窗口过程WndProc函数处理。

       第七步:WndProc函数的switch结构中处理WM_KEYDOWN消息(MessageBox窗口显示按键消息的虚拟键码),处理完之后将控制器交还给Windows操作系统。

       第八步:Windows系统将任务切换到主程序,消息循环GetMessage函数继续从消息队列中获取消息,如果消息队列中没有消息,则继续等待。

请读者写一个实例程序,测试上述消息循环过程。请单步跟踪程序执行的过程。

本文摘自编程达人系列教材《Windows API每日一练》。公众号滴水编程达人。

这篇关于新书推荐:2.3 消息机制的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1048217

相关文章

JVM 的类初始化机制

前言 当你在 Java 程序中new对象时,有没有考虑过 JVM 是如何把静态的字节码(byte code)转化为运行时对象的呢,这个问题看似简单,但清楚的同学相信也不会太多,这篇文章首先介绍 JVM 类初始化的机制,然后给出几个易出错的实例来分析,帮助大家更好理解这个知识点。 JVM 将字节码转化为运行时对象分为三个阶段,分别是:loading 、Linking、initialization

不懂推荐算法也能设计推荐系统

本文以商业化应用推荐为例,告诉我们不懂推荐算法的产品,也能从产品侧出发, 设计出一款不错的推荐系统。 相信很多新手产品,看到算法二字,多是懵圈的。 什么排序算法、最短路径等都是相对传统的算法(注:传统是指科班出身的产品都会接触过)。但对于推荐算法,多数产品对着网上搜到的资源,都会无从下手。特别当某些推荐算法 和 “AI”扯上关系后,更是加大了理解的难度。 但,不了解推荐算法,就无法做推荐系

深入探索协同过滤:从原理到推荐模块案例

文章目录 前言一、协同过滤1. 基于用户的协同过滤(UserCF)2. 基于物品的协同过滤(ItemCF)3. 相似度计算方法 二、相似度计算方法1. 欧氏距离2. 皮尔逊相关系数3. 杰卡德相似系数4. 余弦相似度 三、推荐模块案例1.基于文章的协同过滤推荐功能2.基于用户的协同过滤推荐功能 前言     在信息过载的时代,推荐系统成为连接用户与内容的桥梁。本文聚焦于

防近视护眼台灯什么牌子好?五款防近视效果好的护眼台灯推荐

在家里,灯具是属于离不开的家具,每个大大小小的地方都需要的照亮,所以一盏好灯是必不可少的,每个发挥着作用。而护眼台灯就起了一个保护眼睛,预防近视的作用。可以保护我们在学习,阅读的时候提供一个合适的光线环境,保护我们的眼睛。防近视护眼台灯什么牌子好?那我们怎么选择一个优秀的护眼台灯也是很重要,才能起到最大的护眼效果。下面五款防近视效果好的护眼台灯推荐: 一:六个推荐防近视效果好的护眼台灯的

Java ArrayList扩容机制 (源码解读)

结论:初始长度为10,若所需长度小于1.5倍原长度,则按照1.5倍扩容。若不够用则按照所需长度扩容。 一. 明确类内部重要变量含义         1:数组默认长度         2:这是一个共享的空数组实例,用于明确创建长度为0时的ArrayList ,比如通过 new ArrayList<>(0),ArrayList 内部的数组 elementData 会指向这个 EMPTY_EL

智能交通(二)——Spinger特刊推荐

特刊征稿 01  期刊名称: Autonomous Intelligent Systems  特刊名称: Understanding the Policy Shift  with the Digital Twins in Smart  Transportation and Mobility 截止时间: 开放提交:2024年1月20日 提交截止日

【编程底层思考】垃圾收集机制,GC算法,垃圾收集器类型概述

Java的垃圾收集(Garbage Collection,GC)机制是Java语言的一大特色,它负责自动管理内存的回收,释放不再使用的对象所占用的内存。以下是对Java垃圾收集机制的详细介绍: 一、垃圾收集机制概述: 对象存活判断:垃圾收集器定期检查堆内存中的对象,判断哪些对象是“垃圾”,即不再被任何引用链直接或间接引用的对象。内存回收:将判断为垃圾的对象占用的内存进行回收,以便重新使用。

【Tools】大模型中的自注意力机制

摇来摇去摇碎点点的金黄 伸手牵来一片梦的霞光 南方的小巷推开多情的门窗 年轻和我们歌唱 摇来摇去摇着温柔的阳光 轻轻托起一件梦的衣裳 古老的都市每天都改变模样                      🎵 方芳《摇太阳》 自注意力机制(Self-Attention)是一种在Transformer等大模型中经常使用的注意力机制。该机制通过对输入序列中的每个元素计算与其他元素之间的相似性,

如何通俗理解注意力机制?

1、注意力机制(Attention Mechanism)是机器学习和深度学习中一种模拟人类注意力的方法,用于提高模型在处理大量信息时的效率和效果。通俗地理解,它就像是在一堆信息中找到最重要的部分,把注意力集中在这些关键点上,从而更好地完成任务。以下是几个简单的比喻来帮助理解注意力机制: 2、寻找重点:想象一下,你在阅读一篇文章的时候,有些段落特别重要,你会特别注意这些段落,反复阅读,而对其他部分

【Tools】大模型中的注意力机制

摇来摇去摇碎点点的金黄 伸手牵来一片梦的霞光 南方的小巷推开多情的门窗 年轻和我们歌唱 摇来摇去摇着温柔的阳光 轻轻托起一件梦的衣裳 古老的都市每天都改变模样                      🎵 方芳《摇太阳》 在大模型中,注意力机制是一种重要的技术,它被广泛应用于自然语言处理领域,特别是在机器翻译和语言模型中。 注意力机制的基本思想是通过计算输入序列中各个位置的权重,以确