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 是一个宏,用于标记在函数中未使用的参数。这在编译时避免了未使用参数的警告。这行代码的作用是告诉编译器,这两个参数 hPrevInstance 和 lpCmdLine 在函数体中没有被使用,但这是有意为之,并且这种情况是可以接受的。
在标记未使用的参数后,模板代码就开始从资源文件加载字符串并注册窗口类。
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_TITLE 和 IDC_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 表示这是一个菜单资源。BEGIN 和 END:这些关键字用于定义菜单的开始和结束部分。
POPUP:POPUP 定义了一个包含子菜单的顶级菜单项:
"文件(&F)" 和 "帮助(&H)" 是两个顶级菜单项,它们分别包含一个或多个子菜单项。(&F) 和 (&H) 是快捷键,按下 Alt+F 和 Alt+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 表示检索线程的所有消息;wMsgFilterMin 和 wMsgFilterMax: 指定要检索的消息范围,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 将消息分派到窗口过程,窗口过程根据消息类型执行相应的操作。
最后程序的执行结果:

关于窗口

相关文章:
win32:第一个窗口程序-应用程序入口点(part.6)
第一个窗口程序的最后一部分:应用程序入口函数wWinMain;这是Windows应用程序的主函数,负责初始化应用程序、注册窗口类、创建主窗口并进入消息循环处理消息。 int APIENTRY wWinMain(_In_ HINSTANCE hInstance,_In_opt_ HINSTANCE hPrevInst…...
c++ 多边形 xyz 数据 获取 中心点方法,线的中心点取中心值搞定 已解决
有需求需要对。多边形 获取中心点方法,绝大多数都是 puthon和java版本。立体几何学中的知识。 封装函数 point ##########::getCenterOfGravity(std::vector<point> polygon) {if (polygon.size() < 2)return point();auto Area [](point p0, point p1, p…...
ext_errno:拓展errno
类似于C库的errno机制,报告错误发生的原因以及所在的位置,通过查询来获取。...
【CUDA】 Trust基本特性介绍及性能分析
Trust简介 Thrust 是一个实现了众多基本并行算法的 C 模板库,类似于 C 的标准模板库(standard template library, STL)。该库自动包含在 CUDA 工具箱中。这是一个模板库,仅仅由一些头文件组成。在使用该库的某个功能时,包含需要的头文件即可。该库中的所有类型与函数都在命名空…...
颈肩肌筋膜炎中医治疗
颈肩肌筋膜炎,又称颈肩肌纤维织炎或肌肉风湿症,是一种涉及筋膜、肌肉、肌腱和韧带等软组织的无菌性炎症。以下将分别从症状和治疗两方面进行详细介绍。 一、颈肩肌筋膜炎的症状 颈肩肌筋膜炎的主要症状包括: 1、肩背部疼痛:患者…...
Java 通配符 在短信发送之中 通配符参数动态获取解决方案
目录 1、通配符应用场景 2、实现方案分析 2.1、可能针对不同模板中核定参数硬编码到程序之中写死 2.2、通配置模板之中动态获得对应的参数 3、通过正则表达式验证与替换参数${}参考示例 4、参考文章 1、通配符应用场景 我们在使用通配符场景,主要是应用于短信…...
Mybatis-Plus中LambdaQueryWrapper
基本用法 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; // 假设有一个 User 实体类 LambdaQueryWrapper<User> queryWrapper new LambdaQueryWrapper<>(); // 添加查询条件 queryWrapper.eq(User::getName, "John&quo…...
C++ 入门05:类和对象
往期回顾: C 入门02:控制结构和循环-CSDN博客C 入门03:函数与作用域-CSDN博客C 入门04:数组与字符串-CSDN博客 一、前言 在前面文章的学习中,我们了解了 C 的基本结构、变量、输入输出、控制结构、循环、函数、作用域…...
4G LTE教程
整体架构 物理层(第 1 层) 物理层通过空中接口传输来自 MAC 传输信道的所有信息。负责 RRC 层的链路自适应 (AMC)、功率控制、小区搜索(用于初始同步和切换目的)和其他测量(LTE 系统内部和系统之间)。 介…...
C++:哈希表
哈希表概念 哈希表可以简单理解为:把数据转化为数组的下标,然后用数组的下标对应的值来表示这个数据。如果我们想要搜索这个数据,直接计算出这个数据的下标,然后就可以直接访问数组对应的位置,所以可以用O(1)的复杂度…...
自己动手写一个滑动验证码组件(后端为Spring Boot项目)
近期参加的项目,主管丢给我一个任务,说要支持滑动验证码。我身为50岁的软件攻城狮,当时正背着双手,好像一个受训的保安似的,中规中矩地参加每日站会,心想滑动验证码在今时今日已经是标配了,司空…...
keepalive脑裂
keepalive脑裂 调度器的高可用 vip地址主备之间的切换,主在工作时,p地址只在主上,主停止工作,ip飘移到备服务器。 在主备的优先级不变的情况下,主恢复工作,vip会飘回到主服务器。 1、配优先级 2、配置…...
STM32Cubemx配置生成 Keil AC6支持代码
文章目录 一、前言二、AC 6配置2.1 ARM ComPiler 选择AC62.2 AC6 UTF-8的编译命令会报错 三、STM32Cubemx 配置3.1 找到stm32cubemx的模板位置3.2 替换文件内核文件3.3 修改 cmsis_os.c文件3.4 修改本地 四、编译对比 一、前言 使用keil ARM compiler V5的时候,编译…...
Perl基础入门指南:从零开始掌握Perl编程
Perl是一种功能强大且灵活的编程语言,广泛应用于系统管理、Web开发、网络编程和文本处理等领域。如果你是编程新手或者想学习一种新的编程语言,Perl是一个不错的选择。本文将带你了解Perl的基础知识,并通过简单的示例代码帮助你快速入门。 什…...
Mybatis SQL注解使用场景
MyBatis 提供了几种常用的注解,主要用于简化 XML 映射文件的编写,使得 SQL 查询和操作可以直接在 Java 接口中定义。下面列出了主要的注解以及它们在被调用时的写法示例: 1. Select Select 注解用于执行查询操作,并将查询结果映…...
Dataset for Stable Diffusion
1.Dataset for Stable Diffusion 笔记来源: 1.Flickr8k数据集处理 2.处理Flickr8k数据集 3.Github:pytorch-stable-diffusion 4.Flickr 8k Dataset 5.dataset_flickr8k.json 1.1 Dataset 采用Flicker8k数据集,该数据集有两个文件ÿ…...
近期matlab学习笔记,学习是一个记录,反复的过程
近期matlab学习笔记,学习是一个记录,反复的过程 matlab的mlx文件在运行的时候,不需要在文件夹路径下,也能运行,但是需要调用子函数时,就需要在文件所在路径下运行 那就先运行子函数,把路径换过来…...
Elasticsearch7.5.2 常用rest api与elasticsearch库
目录 一、rest api 1. 新建索引 2. 删除索引 3. 插入单条数据 4. 更新单条数据 5. 删除单条数据 6. 查询数据 二、python elasticsearch库 1. 新建索引 一、rest api 1. 新建索引 请求方式:PUT 请求URL:http://ip/(your_index_nam…...
Autosar Dcm配置-0x28服务ComControl-基于ETAS软件
文章目录 前言DcmDcmDsdDcmDspBswMBswMModeRequestPortBswMModeConditionBswMLogicalExpressionBswMActionBswMActionListBswMRule总结前言 0x28服务主要用来控制非诊断报文的通讯,一般在刷写预编程过程中,用来禁止APP的通信报文,可以减少总线负载率,提高刷写成功率。本文…...
平安养老险厦门分公司:提升金融服务,发挥金融力量
为向社会公众普及金融保险知识,传递消费者权益保护理念,平安养老保险股份有限公司厦门分公司(以下简称“分公司”)积极开展“78保险公众宣传日”系列教育宣传活动。分公司紧扣“保险,让每一步前行更有底气”主题&#…...
利用最小二乘法找圆心和半径
#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …...
在软件开发中正确使用MySQL日期时间类型的深度解析
在日常软件开发场景中,时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志,到供应链系统的物流节点时间戳,时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库,其日期时间类型的…...
51c自动驾驶~合集58
我自己的原文哦~ https://blog.51cto.com/whaosoft/13967107 #CCA-Attention 全局池化局部保留,CCA-Attention为LLM长文本建模带来突破性进展 琶洲实验室、华南理工大学联合推出关键上下文感知注意力机制(CCA-Attention),…...
多场景 OkHttpClient 管理器 - Android 网络通信解决方案
下面是一个完整的 Android 实现,展示如何创建和管理多个 OkHttpClient 实例,分别用于长连接、普通 HTTP 请求和文件下载场景。 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas…...
vscode(仍待补充)
写于2025 6.9 主包将加入vscode这个更权威的圈子 vscode的基本使用 侧边栏 vscode还能连接ssh? debug时使用的launch文件 1.task.json {"tasks": [{"type": "cppbuild","label": "C/C: gcc.exe 生成活动文件"…...
【解密LSTM、GRU如何解决传统RNN梯度消失问题】
解密LSTM与GRU:如何让RNN变得更聪明? 在深度学习的世界里,循环神经网络(RNN)以其卓越的序列数据处理能力广泛应用于自然语言处理、时间序列预测等领域。然而,传统RNN存在的一个严重问题——梯度消失&#…...
【第二十一章 SDIO接口(SDIO)】
第二十一章 SDIO接口 目录 第二十一章 SDIO接口(SDIO) 1 SDIO 主要功能 2 SDIO 总线拓扑 3 SDIO 功能描述 3.1 SDIO 适配器 3.2 SDIOAHB 接口 4 卡功能描述 4.1 卡识别模式 4.2 卡复位 4.3 操作电压范围确认 4.4 卡识别过程 4.5 写数据块 4.6 读数据块 4.7 数据流…...
Java 加密常用的各种算法及其选择
在数字化时代,数据安全至关重要,Java 作为广泛应用的编程语言,提供了丰富的加密算法来保障数据的保密性、完整性和真实性。了解这些常用加密算法及其适用场景,有助于开发者在不同的业务需求中做出正确的选择。 一、对称加密算法…...
【Java_EE】Spring MVC
目录 Spring Web MVC 编辑注解 RestController RequestMapping RequestParam RequestParam RequestBody PathVariable RequestPart 参数传递 注意事项 编辑参数重命名 RequestParam 编辑编辑传递集合 RequestParam 传递JSON数据 编辑RequestBody …...
如何理解 IP 数据报中的 TTL?
目录 前言理解 前言 面试灵魂一问:说说对 IP 数据报中 TTL 的理解?我们都知道,IP 数据报由首部和数据两部分组成,首部又分为两部分:固定部分和可变部分,共占 20 字节,而即将讨论的 TTL 就位于首…...
