win32:第一个窗口程序-应用程序入口点(part.6)

第一个窗口程序的最后一部分:应用程序入口函数wWinMain;这是Windows应用程序的主函数,负责初始化应用程序、注册窗口类、创建主窗口并进入消息循环处理消息。

int APIENTRY wWinMain(_In_ HINSTANCE hInstance,_In_opt_ HINSTANCE hPrevInstance,_In_ LPWSTR    lpCmdLine,_In_ int       nCmdShow)
{UNREFERENCED_PARAMETER(hPrevInstance);UNREFERENCED_PARAMETER(lpCmdLine);
​// 初始化全局字符串LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);LoadStringW(hInstance, IDC_WINDOWSPROJECT1, szWindowClass, MAX_LOADSTRING);MyRegisterClass(hInstance);
​// 执行应用程序初始化:if (!InitInstance (hInstance, nCmdShow)){return FALSE;}
​HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_WINDOWSPROJECT1));
​MSG msg;
​// 主消息循环:while (GetMessage(&msg, nullptr, 0, 0)){if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)){TranslateMessage(&msg);DispatchMessage(&msg);}}
​return (int) msg.wParam;
}
​
函数声明部分
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,_In_opt_ HINSTANCE hPrevInstance,_In_ LPWSTR    lpCmdLine,_In_ int       nCmdShow)

APIENTRY 是一个宏,定义了函数的调用约定;具体来说,APIENTRY 在 Windows 平台上通常定义为 __stdcall__stdcall 是一种调用约定,规定了函数如何接收参数、返回值,以及函数调用时堆栈的清理方式。(这个部分在汇编部分有涉及到,这边再描述一下__stdcall调用约定的一些关键点)

参数传递顺序: 参数从右向左传递(即最后一个参数最先压入堆栈)。
堆栈清理: 函数自身负责清理堆栈。这与__cdecl不同,在__cdecl中,调用者负责清理堆栈。
名称修饰: 在使用__stdcall时,编译器会对函数名进行修饰。这通常包括在函数名前加上一个下划线,并在后面加上@符号和参数的字节数。例如,void MyFunction(int a) 会被修饰为 _MyFunction@4。
应用场景: __stdcall主要用于Win32 API函数以及一些第三方库的接口函数。

接着来说一下程序入口函数的参数列表:

hInstance:是当前应用程序实例的句柄;它是一个唯一标识应用程序的实例,用于加载资源(如图标、字符串、对话框模板等)和其他操作。
hPrevInstance:这是上一个实例的句柄。在 16 位 Windows 中,它用于判断是否已经有一个实例在运行。对于 32 位和 64 位 Windows 应用程序,这个参数总是 NULL,所以一般不需要用它。
lpCmdLine:是指向包含命令行参数的字符串的指针。
nCmdShow:指定应用程序窗口的初始显示状态。这个参数可以有多种值,比如 SW_SHOW、SW_HIDE 等,用于决定窗口是最小化、最大化还是正常显示,通常在创建窗口时传递给 ShowWindow 函数。

在Windows编程中,应用程序的实例(Instance)通常指的是应用程序在内存中的一个运行副本。每个实例都有一个唯一的句柄(HINSTANCE),这是一个标识符,用于区分和管理不同的实例。当你运行一个可执行文件(如 .exe),操作系统会为这个可执行文件分配内存,并启动一个新进程。这个进程就是应用程序的一个实例。你可以同时运行多个相同的可执行文件,每一个运行的进程都是该应用程序的一个实例。

函数体部分
    UNREFERENCED_PARAMETER(hPrevInstance);UNREFERENCED_PARAMETER(lpCmdLine);

UNREFERENCED_PARAMETER 是一个宏,用于标记在函数中未使用的参数。这在编译时避免了未使用参数的警告。这行代码的作用是告诉编译器,这两个参数 hPrevInstancelpCmdLine 在函数体中没有被使用,但这是有意为之,并且这种情况是可以接受的。

在标记未使用的参数后,模板代码就开始从资源文件加载字符串并注册窗口类。

    LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);LoadStringW(hInstance, IDC_WINDOWSPROJECT1, szWindowClass, MAX_LOADSTRING);MyRegisterClass(hInstance);

LoadStringW 是一个Win32 API函数,用于从应用程序的资源文件中加载字符串资源;他的原型是

int LoadStringW(HINSTANCE hInstance,UINT uID,LPWSTR lpBuffer,int cchBufferMax
);

hInstance: 应用程序实例的句柄。在这里,它指定了包含字符串资源的模块。

uID: 字符串资源的标识符。在这里,IDS_APP_TITLEIDC_WINDOWSPROJECT1 是资源ID,通常在资源文件(如 .rc 文件)中定义。

lpBuffer: 指向接收加载的字符串的缓冲区。

cchBufferMax: 缓冲区的最大字符数,包括终止的空字符。

LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);:从资源文件中加载ID为 IDS_APP_TITLE 的字符串,并将其存储在 szTitle 缓冲区中。

LoadStringW(hInstance, IDC_WINDOWSPROJECT1, szWindowClass, MAX_LOADSTRING);:从资源文件中加载ID为 IDC_WINDOWSPROJECT1 的字符串,并将其存储在 szWindowClass 缓冲区中。

通过查看项目中的资源文件(.rc)的内容就可以找到载入的字符串是什么

MyRegisterClass(hInstance);接着就是调用自定义的注册窗口类函数,去指定窗口的样式、窗口过程(处理窗口消息的回调函数)、窗口背景色等信息。(part.2)

接着就是需要进行应用程序实例的初始化:这里调用了自定义函数InitInstance;在这个函数中我们会创建实例的主窗口,并根据nCmdShow参数指定程序窗口的显示方式。

 if (!InitInstance (hInstance, nCmdShow)){return FALSE;}

若实例初始化失败,则返回false,如若成功则显示主窗口。在实例初始化成功后加载加速键表(accelerator table),以便在消息循环中处理快捷键。

HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_WINDOWSPROJECT1));

LoadAccelerators 是一个Win32 API函数,用于加载加速键表。加速键表定义了一组快捷键及其对应的命令,可以用来快捷地执行菜单命令。其原型如下:

HACCEL LoadAccelerators(HINSTANCE hInstance,LPCWSTR lpTableName
);

hInstance: 应用程序实例的句柄,指定包含加速键表的模块。

lpTableName: 指向包含加速键表的资源名称或标识符(通常使用 MAKEINTRESOURCE 宏转换资源ID)。

当前项目的rc文件中的资源设置如下:

这是菜单资源的标识符和类型。IDC_WINDOWSPROJECT1 是菜单的ID,MENU 表示这是一个菜单资源。BEGINEND:这些关键字用于定义菜单的开始和结束部分。

POPUP:POPUP 定义了一个包含子菜单的顶级菜单项:

"文件(&F)""帮助(&H)" 是两个顶级菜单项,它们分别包含一个或多个子菜单项。(&F)(&H) 是快捷键,按下 Alt+FAlt+H 可以打开相应的菜单。

MENUITEM:MENUITEM 定义了一个具体的菜单项:

"退出(&X)", IDM_EXIT 定义了一个名为 "退出" 的菜单项,(&X) 是快捷键,(&X) 是快捷键,IDM_EXIT 是菜单项的命令ID。

"关于(&A) ...", IDM_ABOUT 定义了一个名为 "关于" 的菜单项,(&A) 是快捷键,IDM_ABOUT 是菜单项的命令ID。

接着进行消息变量声明:

MSG msg;

MSG 结构体用于存储从消息队列中检索的消息,消息循环中会使用这个结构体来接收和处理窗口消息。MSG 结构体在 winuser.h 头文件中定义,用于包含窗口消息信息:

typedef struct tagMSG {HWND   hwnd;UINT   message;WPARAM wParam;LPARAM lParam;DWORD  time;POINT  pt;DWORD  lPrivate;
} MSG, *PMSG;

hwnd: 接收消息的窗口句柄,message: 消息标识符(如 WM_PAINT, WM_KEYDOWN),以及其他参数:

wParam: 消息的附加信息,具体内容取决于消息类型。
lParam: 消息的附加信息,具体内容取决于消息类型。
time: 消息被放入消息队列的时间戳。
pt: POINT 结构体,表示消息发生时的光标位置。
lPrivate: 私有数据,用于内部用途。

声明变量后接着就需要实现消息循环:它在应用程序的整个生命周期中不断运行,处理来自操作系统和用户的各种消息。

while (GetMessage(&msg, nullptr, 0, 0)){if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)){TranslateMessage(&msg);DispatchMessage(&msg);}}

GetMessage 函数从调用线程的消息队列中检索消息,并将其存储在 MSG 结构体中。lpMsg: 指向 MSG 结构体的指针,用于接收消息;hWnd: 指定消息的窗口句柄,nullptr 表示检索线程的所有消息;wMsgFilterMinwMsgFilterMax: 指定要检索的消息范围,0, 0 表示检索所有消息。

TranslateAccelerator 函数将加速键消息转换为命令消息,hWnd: 接收消息的窗口句柄;hAccTable: 加速键表句柄;lpMsg: 指向 MSG 结构体的指针。加速键(Accelerator Key)消息是指在 Windows 应用程序中用于快捷键操作的一种消息类型。

TranslateMessage 函数将虚拟键消息(如 WM_KEYDOWN)转换为字符消息(如 WM_CHAR);虚拟键消息(Virtual Key Messages)是 Windows 操作系统中用于处理键盘输入的一种消息类型。它们是由键盘驱动程序生成的消息,通常通过输入设备(如键盘)上的按键触发。

DispatchMessage 函数将消息分派到窗口过程(Window Procedure),窗口过程根据消息类型执行相应的操作。

消息循环的完整流程

检索消息GetMessage 从消息队列中检索消息并存储在 msg 结构体中;如果 GetMessage 返回 0,表示收到 WM_QUIT 消息,退出消息循环。

处理加速键TranslateAccelerator 检查消息是否为加速键,如果是,则翻译并处理它,如果 TranslateAccelerator 返回 TRUE,表示消息已处理,不需要进一步处理。

翻译和分派消息:如果消息不是加速键或未处理,调用 TranslateMessage 将虚拟键消息转换为字符消息;调用 DispatchMessage 将消息分派到窗口过程,窗口过程根据消息类型执行相应的操作。

最后程序的执行结果:

关于窗口

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/46007.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

pytorch说明

深度学习中的重要概念: 激活函数: 激活函数的必要性:激活函数不是绝对必须的,但在深度学习中,它们几乎总是被使用。激活函数可以引入非线性,这使得神经网络能够学习更复杂的模式。 激活函数的位置&#x…

用HTML和CSS实现提示工具(tooltip)及HTML元素的定位

所谓提示工具,是指将鼠标移动到某个HTML元素(工具)时会显示一些提示内容(提示文本),而鼠标移出工具元素的范围时提示文本就消失了。考虑到提示文本元素应当在鼠标进入工具元素时显示,鼠标离开工…

Mac安装stable diffusion 工具

文章目录 1.安装 Homebrew2.安装 stable diffusion webui 的依赖3.下载 stable diffusion webui 代码4.启动 stable diffusion webui 本体5.下载模型6.这里可能会遇到一个clip-vit-large-patch14报错 参考:https://brew.idayer.com/install/stable-diffusion-webui/…

STM32入门开发操作记录(二)——LED与蜂鸣器

目录 一、工程模板二、点亮主板1. 配置寄存器2. 调用库函数 三、LED1. 闪烁2. 流水灯 四、蜂鸣器 一、工程模板 参照第一篇,新建工程目录ProjectMould,将先前打包好的Start,Library和User文件^C^V过来,并在Keil5内完成器件支持包的…

jenkins系列-01.docker安装jenkins

进入官网:https://www.jenkins.io/ 使用LONG term support版本:2.387.1 docker pull jenkins/jenkins:2.387.1-lts 拉取镜像: 编写docker-compose文件: 启动jenkins: 查看启动日志: 默认生成的密码:…

基于springboot+vue+uniapp的超市购物系统小程序

开发语言:Java框架:springbootuniappJDK版本:JDK1.8服务器:tomcat7数据库:mysql 5.7(一定要5.7版本)数据库工具:Navicat11开发软件:eclipse/myeclipse/ideaMaven包&#…

LeetCode 142.环形链表2 C写法

LeetCOde 142.环形链表2 C写法 思路1🤔: ​ 用环形链表的方法,快慢指针找到slow和fast的相遇点,此时头到入口点的位置与相遇点到入口点的距离一样。 ​ 我们假设头到入口点的长度为L,环的长度为C,相遇点到入…

Rust 测试的组织结构

测试的组织结构 本章一开始就提到,测试是一个复杂的概念,而且不同的开发者也采用不同的技术和组织。Rust 社区倾向于根据测试的两个主要分类来考虑问题:单元测试(unit tests)与 集成测试(integration test…

负荷预测 | Matlab基于Transformer-LSTM多变量时间序列多步预测

目录 效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.Matlab基于Transformer-LSTM多变量时间序列多步预测; 2.多变量时间序列数据集(负荷数据集),采用前96*2个时刻预测的特征和负荷数据预测未来96个时刻的负荷数据&#x…

记一次饱经挫折的阿里云ROS部署经历

前言 最近在参加的几个项目测评里,我发现**“一键部署”这功能真心好用,省下了不少宝贵时间和力气,再加上看到阿里云现在有个开源上云**的活动。趁着这波热潮,今天就聊聊怎么从头开始,一步步搞定阿里云的资源编排服务…

【持续集成_06课_Jenkins高级pipeline应用】

一、创建项目选择pipeline的风格 它主要是以脚本(它自己的语言)的方式进行运行,一般由运维去做的事情,作为测试而言。了解即可。 --- 体现形式全部通过脚本去实现:执行之前(拉取代码)执行&…

Linux:Linux网络总结(附下载链接)

文章目录 下载链接网络问题综合问题访问一个网页的全过程?WebSocket HTTPHTTP基本概念GET与POSTHTTP特性HTTP缓存技术HTTP的演变HTTP1.1 优化 HTTPSHTTP与HTTPS有哪些区别?HTTPS解决了HTTP的哪些问题?HTTPS如何解决的?HTTPS是如何…

# Redis 入门到精通(二)通用指令

Redis 入门到精通(二)通用指令 一、redis 通用指令-key 基本操作 1、key 特征 key是一个字符串,通过key获取redis中保存的数据。 2、key 应该设计哪些操作? 对于 key 自身状态的相关操作,例如:删除,判定存在&…

企业网络实验(vmware虚拟机充当DHCP服务器)所有IP全部保留,只为已知mac分配固定IP

文章目录 需求实验修改dhcp虚拟机配置文件测试PC获取IP查看user-bind 需求 (vmware虚拟机充当DHCP服务器)所有IP全部保留,只为已知mac分配固定IP 实验 前期配置: https://blog.csdn.net/xzzteach/article/details/140406092 后续配置均在以上配置的前…

keepalive和haproxy

1、keepalive 1.1概念 调度器的高可用 vip地址主备之间的切换,主在工作时,vip地址只在主上,主停止工作,vip漂移到备服务器 在主备的优先级不变的情况下,主恢复工作,vip会飘回到主服务器 1、配优先级 …

【RabbitMQ】一文详解消息可靠性

目录: 1.前言 2.生产者 3.数据持久化 4.消费者 5.死信队列 1.前言 RabbitMQ 是一款高性能、高可靠性的消息中间件,广泛应用于分布式系统中。它允许系统中的各个模块进行异步通信,提供了高度的灵活性和可伸缩性。然而,这种通…

.NET MAUI开源架构_1.学习资源分享

最近需要开发Android的App,想预研下使用.NET开源架构.NET MAUI来开发App程序。因此网上搜索了下相关资料,现在把我查询的结果记录下,方便后面学习。 1.官方文档 1.1MAUI官方学习网站 .NET Multi-Platform App UI 文档 - .NET MAUI | Micro…

Open-TeleVision——通过VR沉浸式感受人形机器人视野:兼备远程控制和深度感知能力

前言 7.3日,我司七月在线(集AI大模型职教、应用开发、机器人解决方案为一体的科技公司)的「大模型机器人(具身智能)线下营」群里的一学员发了《Open-TeleVision: Teleoperation with Immersive Active Visual Feedback》这篇论文的链接,我当时快速看了一…

shell脚本之if/case语句

一、条件测试 1、1 返回码 $? $? :返回码,用来判断命令或者脚本是否执行成功。 0 :表示true ,成功;非0 则表示flase ,失败。 1、2 test命令 可以进行条件测试,然后根据返回值来判断条件是否成立 -e…

RISC-V异常处理流程概述(2):异常处理机制

RISC-V异常处理流程概述(2):异常处理机制 一、异常处理流程和异常委托1.1 异常处理流程1.2 异常委托二、RISC-V异常处理中软件相关内容2.1 异常处理准备工作2.2 异常处理函数2.3 Opensbi系统调用的注册一、异常处理流程和异常委托 1.1 异常处理流程 发生异常时,首先需要执…