理解MiniGUI消息循环和窗口过程

2024-01-17 21:36

本文主要是介绍理解MiniGUI消息循环和窗口过程,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

消息和消息循环

在Windows系列操作系统中,广泛使用了消息驱动的概念。在MiniGUI中,我们也使用了消息驱动作为应用程序的创建构架。

消息驱动的含义就是:程序的流程不再是只有一个入口和若干个出口的串行执行路线。相反,程序会一直处于一个循环状态,在这个循环当中,程序从外部输入设备获取某些事件,比如用户的案件或者鼠标的移动,然后根据这些事件作出某种响应,并完成一定的功能,这个循环直到程序接受到某个消息为止。事件驱动的底层设施,就是常说的消息队列和消息循环。

消息循环就是一个循环体,在这个循环体中,程序利用GetMesage函数不停从消息队列中获得消息,然后利用DispatchMessage函数将消息发送到指定的窗口,也就是调用指定窗口的窗口过程,并传递消息及其参数。定性的消息循环如下所示:

  while (GetMessage (&Msg, hMainWnd)) {TranslateMessage (&Msg);DispatchMessage (&Msg);}

如上所示,GetMessage 函数从 hMainWnd 窗口所属的消息队列当中获得消息,然后调用 TranslateMessage 函数将 MSG_KEYDOWN 和 MSG_KEYUP 消息翻译成 MSG_CHAR 消息,最后调用 DispatchMessage 函数将消息发送到指定的窗口。

在 MiniGUI-Threads 版本中,每个建立有窗口的 GUI 线程有自己的消息队列,而且,所有属于同一线程的窗口共享同一个消息队列。因此,GetMessage 函数将获得所有与 hMainWnd 窗口在同一线程中的窗口的消息。
  
  而在 MiniGUI-Lite 版本中,只有一个消息队列,GetMessage 将从该消息队列当中获得所有的消息,而忽略 hMainWnd 参数。 

消息驱动的应用程序中,计算机外设发生的事件,例如键盘键的敲击、鼠标键的按击等,都由支持系统收集,将其以事先的约定格式翻译为特定的消息。应用程序一般包含有自己的消息队列,系统将消息发送到应用程序的消息队列中。应用程序可以建立一个循环,在这个循环中读取消息并处理消息,一直处理到特定的消息传来为止。这样的循环称为消息循环。一般地,消息由代表消息的一个整型数和消息的附加参数组成。例如,鼠标左键的按下消息,可能由133这个数来表示,其附加参数可能包含按下时的鼠标所在位置信息。例如,MiniGUI中如下定义消息:

typedef struct
{HWND             hwnd;int              message;WPARAM           wParam;LPARAM           lParam;...
}MSG;

message 指定了特定的消息类型,wParam 是以unsigned int类型定义的消息的短参数,lParam 是以 long 类型定义的消息长参数。

应用程序一般要提供一个处理消息的标准函数。在消息循环中,系统可以调用此函数,应用程序在此函数中处理相应消息。

窗口过程和窗口类

窗口过程是用来处理窗口消息的函数过程。对于同一类型的控件,其窗口过程一般是一样的。因此,系统一般利用窗口的窗口类名来区分不通的窗口类并调用不同的窗口过程。由于几乎每一个主窗口均和其他窗口有着不同的窗口过程,因此,在MiniGUI中,窗口类的概念只存在于控件和窗片中。对于主窗口来说,其窗口过程在建立主窗口时指定,而对于控件和窗片俩说,则在注册窗口类时指定,而在建立窗片或控件时指定所属窗口类。

句柄

句柄是 MiniGUI 用来标识对象的标识符。句柄和指针概念类似,但它不一定是指针值。利用句柄,MiniGUI 将系统变量从应用项目中分离了出来,因为程序员只能通过句柄访问对象,因而就没有利用指针是可能发生的因非法访问而导致的数据不一致问题。

在 MiniGUI 中,窗口、控件、设备环境、菜单、图标等均使用句柄访问。

窗口

应用程序和主窗口

我们将基于MiniGUI的一个会话(session)称为一个应用项目,而其中每隔单独的线程或线程组称为应用。每个应用项目可建立多个应用。主窗口时建立在MiniGUI基础上的应用的主界面。MiniGUI为每个主窗口建立单独的消息队列,在该主窗口基础上派生出的创片、对话框及其控件均使用同一消息队列。在MiniGUI中,每个应用对应于一个线程。理论上讲,每个应用可以具备多个主窗口,但是在MiniGUI中,主窗口均以单独的线程实现。但多个主窗口对应单一线程的情况也是可以在miniGUI中实现的。

每个应用项目有一个MiniGUIMain函数,在这个函数中,可建立初始的应用线程,在调用MiniGUIMain之前,MiniGUI启动自己的桌面窗口(Desktop)。桌面窗口作为MiniGUI的窗口管理器而存在。下面的代码段在miniGUIMain中启动了三个主窗口线程:

int MiniGUIMain(int args, char* arg[])
{pthread_t thread, thread2, thread3;CreateThreadForMainWindow(&thread, NULL, TestWindowMain, 0);CreateThreadForMainWindow(&thread2, NULL, TestWindowMain2, 0);CreateThreadForMainWindow(&thread3, NULL, TestWindowMain3, 0);return 0;
}

CreateThreadForMainWindow 函数为主窗口建立线程,并返回线程标识符。

其中的第三个参数是线程的入口函数地址。如下的代码段定义了上述代码中第一个主窗口线程的入口函数:

void InitCreateInfo(PMAINWINCREATE pCreateInfo)
{pCreateInfo->dwStyle = WS_THICKFRAME;pCreateInfo->spCaption = "The first main window" ;pCreateInfo->hMenu = 0;pCreateInfo->hCursor = GetSystemCursor(2);pCreateInfo->hIcon = LoadIconFromFile("res/table.ico");pCreateInfo->MainWindowProc = TestMainWinProc;pCreateInfo->lx = 50; pCreateInfo->ty = 50;pCreateInfo->rx = 300;pCreateInfo->by = 480;pCreateInfo->iBkColor = COLOR_lightwhite; pCreateInfo->dwAddData1 = 0;pCreateInfo->dwAddData2 = 0;
}void* TestWindowMain(void* data)
{MSG Msg;MAINWINCREATE CreateInfo;HWND hMainWnd;InitCreateInfo(&CreateInfo);if( !(hMainWnd = CreateMainWindow(&CreateInfo)) )return NULL;ShowWindow(hMainWnd, SW_SHOWNORMAL);while( GetMessage(&Msg, hMainWnd) ) {DispatchMessage(&Msg);}MainWindowThreadCleanup(hMainWnd);return NULL;
}

在上面的代码段中,该线程首先调用 CreateMainWindow建立了主窗口,然后调用 ShowWindow显示了主窗口,最后启动了消息循环。当消息循环因为接收到 MSG_QUIT 消息而终止时,该函数调用了 MainWindowThreadCleanup 清除了相关的线程数据。

从上述代码中可看出主函数不支持窗口类,在调用CreateMainWindow函数时直接指定主窗口的窗口过程地址。我们也可以从中看到主窗口所支持的其他属性。

MiniGUI 支持的主窗口风格

风格

描述

WS_BORDER

创建一个具有单线边框的窗口

WS_THICKFRAME

创建一个具有宽边框的窗口

WS_THINFRAME

创建一个具有细边框的窗口

WS_CAPTION

创建一个具有标题栏的窗口

WS_HSCROLL

创建一个具有水平滚动条的窗口

WS_MAXMIZEBOX

创建一个具有最大化框的窗口

WS_MINIMIZEBOX

创建一个具有最小化框的窗口

WS_SYSMENU

创建一个具有系统菜单的窗口

WS_VSCROLL

创建一个具有垂直滚动条的窗口

WS_DISABLED

创建一个初始为禁止的窗口

WS_MAXIMIZE

创建一个初始最大化的窗口

WS_MINIMIZE

创建一个初始最小化的窗口

WS_VISIBLE

创建一个初始可见的窗口

WS_EX_TOPMOST

创建一个顶层窗口,这是一个 Win32 的扩展风格

几个重要的消息处理函数 

除了上面提到的 GetMessage 和 TranslateMessage、DispatchMessage 函数以外,MiniGUI 支持如下几个消息处理函数。

PostMessage

该函数将消息放到指定窗口的消息队列后立即返回。这种发送方式称为“邮寄”消息。如果消息队列中邮寄消息缓冲区已满,则该函数返回错误值。在下一个消息循环中,由GetMessage函数获得这个消息之后,窗口才会处理该消息。PostMessage一般用于发送一些非关键性消息。比如在MiniGUI中,鼠标和键盘消息就是通过PostMessage函数发送的。

SendMessage

该函数和PostMessage函数不通,它在发送一条消息给指定窗口时,将等待该消息被处理后才会返回。当需要指定某个消息的处理结果时,使用该函数发送消息,然后根据其返回值进行处理。在MiniGUI-Threads当中,如果发送消息的线程和接收消息的线程不是同一个线程,发送消息的线程将阻塞并等待另一个线程的处理结果,然后继续运行。否则,SendMessage函数将直接调用接收消息窗口的窗口过程函数。MiniGUI-Lite则和上面的第二种情况一样,直接调用接收消息窗口的过程函数。

SendNotifyMessage

该函数和 PostMessage 消息类似,也是不等待消息被处理即返回。但和 PostMessage 消息不同,通过该函数发送的消息不会因为缓冲区满而丢失,因为系统采用链表的形式处理这种消息。通过该函数发送的消息一般称为"通知消息",一般用来从控件向其父窗口发送通知消息。

PostQuitMessage

该消息在消息队列中设置一个 QS_QUIT 标志。GetMessage 在从指定消息队列中获取消息时,会检查该标志,如果有 QS_QUIT 标志,GetMessage 消息将返回 FALSE,从而可以利用该返回值终止消息循环。

这篇关于理解MiniGUI消息循环和窗口过程的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

浅析Spring Security认证过程

类图 为了方便理解Spring Security认证流程,特意画了如下的类图,包含相关的核心认证类 概述 核心验证器 AuthenticationManager 该对象提供了认证方法的入口,接收一个Authentiaton对象作为参数; public interface AuthenticationManager {Authentication authenticate(Authenti

作业提交过程之HDFSMapReduce

作业提交全过程详解 (1)作业提交 第1步:Client调用job.waitForCompletion方法,向整个集群提交MapReduce作业。 第2步:Client向RM申请一个作业id。 第3步:RM给Client返回该job资源的提交路径和作业id。 第4步:Client提交jar包、切片信息和配置文件到指定的资源提交路径。 第5步:Client提交完资源后,向RM申请运行MrAp

好题——hdu2522(小数问题:求1/n的第一个循环节)

好喜欢这题,第一次做小数问题,一开始真心没思路,然后参考了网上的一些资料。 知识点***********************************无限不循环小数即无理数,不能写作两整数之比*****************************(一开始没想到,小学没学好) 此题1/n肯定是一个有限循环小数,了解这些后就能做此题了。 按照除法的机制,用一个函数表示出来就可以了,代码如下

认识、理解、分类——acm之搜索

普通搜索方法有两种:1、广度优先搜索;2、深度优先搜索; 更多搜索方法: 3、双向广度优先搜索; 4、启发式搜索(包括A*算法等); 搜索通常会用到的知识点:状态压缩(位压缩,利用hash思想压缩)。

【机器学习】高斯过程的基本概念和应用领域以及在python中的实例

引言 高斯过程(Gaussian Process,简称GP)是一种概率模型,用于描述一组随机变量的联合概率分布,其中任何一个有限维度的子集都具有高斯分布 文章目录 引言一、高斯过程1.1 基本定义1.1.1 随机过程1.1.2 高斯分布 1.2 高斯过程的特性1.2.1 联合高斯性1.2.2 均值函数1.2.3 协方差函数(或核函数) 1.3 核函数1.4 高斯过程回归(Gauss

【生成模型系列(初级)】嵌入(Embedding)方程——自然语言处理的数学灵魂【通俗理解】

【通俗理解】嵌入(Embedding)方程——自然语言处理的数学灵魂 关键词提炼 #嵌入方程 #自然语言处理 #词向量 #机器学习 #神经网络 #向量空间模型 #Siri #Google翻译 #AlexNet 第一节:嵌入方程的类比与核心概念【尽可能通俗】 嵌入方程可以被看作是自然语言处理中的“翻译机”,它将文本中的单词或短语转换成计算机能够理解的数学形式,即向量。 正如翻译机将一种语言

【C++高阶】C++类型转换全攻略:深入理解并高效应用

📝个人主页🌹:Eternity._ ⏩收录专栏⏪:C++ “ 登神长阶 ” 🤡往期回顾🤡:C++ 智能指针 🌹🌹期待您的关注 🌹🌹 ❀C++的类型转换 📒1. C语言中的类型转换📚2. C++强制类型转换⛰️static_cast🌞reinterpret_cast⭐const_cast🍁dynamic_cast 📜3. C++强制类型转换的原因📝

深入理解RxJava:响应式编程的现代方式

在当今的软件开发世界中,异步编程和事件驱动的架构变得越来越重要。RxJava,作为响应式编程(Reactive Programming)的一个流行库,为Java和Android开发者提供了一种强大的方式来处理异步任务和事件流。本文将深入探讨RxJava的核心概念、优势以及如何在实际项目中应用它。 文章目录 💯 什么是RxJava?💯 响应式编程的优势💯 RxJava的核心概念

poj3750约瑟夫环,循环队列

Description 有N个小孩围成一圈,给他们从1开始依次编号,现指定从第W个开始报数,报到第S个时,该小孩出列,然后从下一个小孩开始报数,仍是报到S个出列,如此重复下去,直到所有的小孩都出列(总人数不足S个时将循环报数),求小孩出列的顺序。 Input 第一行输入小孩的人数N(N<=64) 接下来每行输入一个小孩的名字(人名不超过15个字符) 最后一行输入W,S (W < N),用

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

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