Win32:第一个窗口程序-注册窗口类(Part.2)

news2025/1/22 13:05:57

在part 1中我们阐述了窗口模板程序中的相关宏、全局函数和相关函数声明后我们Part2就来说一下part 1中声明的一个函数MyRegisterClass注册窗口类函数(函数中也使用到了定义的一些全局变量),为什么要注册窗口类在part 1中已经阐述过了,这边就不再说了,那么这个时候直接上代码:

ATOM MyRegisterClass(HINSTANCE hInstance)
{
    WNDCLASSEXW wcex;
​
    wcex.cbSize = sizeof(WNDCLASSEX);
​
    wcex.style          = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc    = WndProc;
    wcex.cbClsExtra     = 0;
    wcex.cbWndExtra     = 0;
    wcex.hInstance      = hInstance;
    wcex.hIcon          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_WINDOWSPROJECT1));
    wcex.hCursor        = LoadCursor(nullptr, IDC_ARROW);
    wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
    wcex.lpszMenuName   = MAKEINTRESOURCEW(IDC_WINDOWSPROJECT1);
    wcex.lpszClassName  = szWindowClass;
    wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
​
    return RegisterClassExW(&wcex);
}

以下代码片段定义了一个函数 MyRegisterClass,用于注册窗口类;窗口类包含了一组与窗口相关的属性,并将这些属性与窗口过程关联起来。在 Windows 程序设计中,窗口类注册是创建窗口的第一步。以下是对代码的详细解释:

函数签名和参数
ATOM MyRegisterClass(HINSTANCE hInstance)

ATOM:函数返回一个 ATOM 类型值,这是一种 Windows 类型,用于标识已注册的窗口类。

HINSTANCE hInstance:这是一个实例句柄,标识应用程序的实例;它通常在 WinMain 函数中传递给 MyRegisterClass

此处跟我再part1中函数声明解释中写的一致。

函数实现
WNDCLASSEXW wcex;

定义一个 WNDCLASSEXW 结构体变量 wcex,用于描述窗口类的属性;通过f12我们可以找到WNDCLASSEXW结构体的具体定义:

typedef struct tagWNDCLASSEXW {
    UINT        cbSize;
    /* Win 3.x */
    UINT        style;
    WNDPROC     lpfnWndProc;
    int         cbClsExtra;
    int         cbWndExtra;
    HINSTANCE   hInstance;
    HICON       hIcon;
    HCURSOR     hCursor;
    HBRUSH      hbrBackground;
    LPCWSTR     lpszMenuName;
    LPCWSTR     lpszClassName;
    /* Win 4.0 */
    HICON       hIconSm;
} WNDCLASSEXW, *PWNDCLASSEXW, NEAR *NPWNDCLASSEXW, FAR *LPWNDCLASSEXW;

接下去就是对刚才定义的结构体变量wcex中的成员变量进行赋值。

wcex.cbSize = sizeof(WNDCLASSEX);

这行代码在 MyRegisterClass 函数中设置 WNDCLASSEX 结构体的 cbSize 成员为 WNDCLASSEX 结构体的大小。这是注册窗口类时必需的一步,确保 Windows 能正确处理这个结构体。

cbSize: 这是 WNDCLASSEXW 结构体中的一个成员,表示该结构体的大小(以字节为单位)。这是一个 UINT 类型的变量。

sizeof(WNDCLASSEX): 这是一个运算符,用于计算 WNDCLASSEX 结构体的大小(以字节为单位);WNDCLASSEXWNDCLASSEXW 的别名,用于处理宽字符(Unicode)版本的窗口类信息。

为什么需要设置cbsize

在 Windows API 中,许多函数需要结构体的大小作为参数,以确保在不同版本的 Windows 中能够正确处理数据结构。设置 cbSize 可以让 API 函数知道传递给它的结构体的确切大小,从而避免因版本或编译器差异导致的内存错误或兼容性问题。
设置窗口类的属性
①定义了窗口类的重绘行为
wcex.style = CS_HREDRAW | CS_VREDRAW;

这行代码设置了 WNDCLASSEX 结构体的 style 成员,指定了窗口类的样式,具体来说,CS_HREDRAWCS_VREDRAW 是两个常量,定义了窗口类的重绘行为。

常量解释
  • CS_HREDRAW:水平重绘,当窗口的宽度改变时,窗口将被完全重绘。

  • CS_VREDRAW:垂直重绘,当窗口的高度改变时,窗口将被完全重绘。

为什么要使用这些样式?

当窗口的大小发生变化时(例如用户调整窗口大小),CS_HREDRAWCS_VREDRAW 确保窗口的内容被正确地重新绘制。这对于需要动态调整窗口内容的应用程序非常重要。

②指定窗口过程
wcex.lpfnWndProc = WndProc;

这行代码将 WNDCLASSEX 结构体的 lpfnWndProc 成员设置为 WndProc 函数的指针。lpfnWndProc 是一个指向窗口过程(Window Procedure)函数的指针,窗口过程是处理所有窗口消息的核心函数。窗口过程是一个回调函数,用于处理来自 Windows 操作系统的各种消息。(具体实现细节在part4进行刨析,到时候结合食用)

③分配窗口类或实例额外内存
wcex.cbClsExtra     = 0;
wcex.cbWndExtra     = 0;

这两行代码在 WNDCLASSEX 结构体中设置了 cbClsExtracbWndExtra 成员,分别为类和窗口分配的额外内存字节数。将它们设置为 0 表示不需要为窗口类或窗口实例分配额外的内存。

cbClsExtra:允许为窗口类附加额外的类级别信息,这些信息可以在窗口类的所有实例之间共享;通常为 0,表示不需要分配额外的内存。

cbWndExtra:允许为每个窗口实例附加额外的实例级别信息,这些信息只能在该窗口实例中使用;通常也0,表示不需要分配额外的内存。

④将成员设置传递至程序实例句柄
wcex.hInstance = hInstance;

这行代码将 WNDCLASSEX 结构体的 hInstance 成员设置为 hInstance,即传递给 MyRegisterClass 函数的实例句柄;hInstance` 是应用程序实例的句柄,用于标识当前运行的应用程序实例。

为什么需要设置 hInstance

设置 wcex.hInstance = hInstance; 告诉 Windows 操作系统这个窗口类是属于哪个应用程序实例的。这样,操作系统可以正确地从这个实例加载资源,如图标、光标、菜单等。

⑤设置默认图标
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_WINDOWSPROJECT1));

这行代码将 WNDCLASSEX 结构体的 hIcon 成员设置为一个图标句柄,这个图标将用作窗口类的默认图标。以下是相关代码的解释:

1)hIcon变量
类型:HICON
作用:指定窗口类的默认图标。
显示位置:用于窗口的标题栏和任务切换界面(如 Alt+Tab 切换窗口时显示的图标)。
2)LoadIcon函数

函数原型:

HICON LoadIcon(HINSTANCE hInstance, LPCTSTR lpIconName);

相关参数:

hInstance:应用程序实例句柄,用于标识从哪个实例加载资源。
lpIconName:图标资源的标识符,可以是资源标识符或资源名称。
3)MAKEINTRESOURCE 宏
作用:将整数资源标识符转换为资源名称(LPCTSTR 类型)。
4)IDI_WINDOWSPROJECT1资源标识符

IDI_WINDOWSPROJECT1 是一个资源标识符,用于标识项目中定义的图标资源。在 Windows 应用程序中,资源通常包括图标、光标、字符串、对话框模板等,这些资源可以在资源脚本文件(通常是 .rc 文件)中定义和引用。

总结:

最后我们可以知道这行代码的意思是从当前应用程序实例中加载标识符为 IDI_WINDOWSPROJECT1 的图标,并将其设置为窗口类的默认图标。

若是要修改默认图标则需要打开项目中对应的rc文件;

右击文件->打开方式->源代码(文本)编辑器

根据源码中设置的资源标识符(我的文件标识符为IDI_WINDOWSPROJECT1)找到如下内容:

我们可以将ICON后的内容指定为我们要设置的图标的路径(要将图片放在项目文件夹中)

IDI_WINDOWSPROJECT1 ICON "path_to_existing_icon.ico"

⑥设置光标句柄
 wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);

这行代码将 WNDCLASSEX 结构体的 hCursor 成员设置为一个光标句柄,该光标将用作窗口类的默认光标。

hCursor成员:

类型:HCURSOR
作用:指定窗口类的默认光标。
显示位置:当鼠标指针位于窗口客户端区域时显示的光标。

LoadCursor 函数:

函数原型:

HCURSOR LoadCursor(HINSTANCE hInstance, LPCTSTR lpCursorName);

参数:

hInstance:应用程序实例句柄。如果加载的是标准光标,则设置为 nullptr。
lpCursorName:光标资源的名称或标识符。如果加载的是标准光标,可以使用预定义的光标标识符。

传入参数:

nullptr:表示加载标准光标,而不是自定义光标资源。
IDC_ARROW:预定义的光标标识符,表示标准箭头光标。

通过调用 LoadCursor 函数并传入 nullptrIDC_ARROW,可以加载系统提供的标准箭头光标,并将其句柄赋值给 wcex.hCursor

⑦设置窗口背景
wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);

这行代码设置了窗口类的背景刷,使得窗口在创建时具有特定的背景颜色;以下是详细解释:

hbrBackground成员变量:

类型:HBRUSH
作用:指定窗口的背景刷,当窗口需要重绘背景时,系统会使用这个刷子填充窗口的背景区域。
COLOR_WINDOW
类型:系统颜色常量
作用:表示系统窗口的默认背景颜色;这个颜色通常是一个淡灰色,具体颜色根据系统主题或用户设置可能会有所不同。
COLOR_WINDOW + 1
在 Windows API 中,系统颜色常量(如 COLOR_WINDOW)是从 1 开始的整数索引,用于标识各种系统颜色。为了将这些整数索引转换为可以使用的刷子句柄,通常需要加 1。
具体地说,COLOR_WINDOW 表示一个系统颜色索引值。
COLOR_WINDOW + 1 是一个特殊的转换,使得可以使用这个索引值作为背景刷。

(HBRUSH)(COLOR_WINDOW + 1):通过这种方式将系统颜色索引转换为一个 HBRUSH 类型的刷子句柄,使其可以赋值给 wcex.hbrBackground

总结:

通过设置 wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);我们可以将窗口的背景刷设为系统默认的窗口背景颜色,当窗口需要重绘背景时,系统将使用这个刷子填充背景区域。这可以确保窗口具有一致的外观,符合用户的系统主题和设置。

⑧设置菜单名
 wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_WINDOWSPROJECT1);

这行代码设置了窗口类的菜单名称,使得窗口可以包含一个菜单。

lpszMenuName成员:

类型:LPCWSTR
作用:指定与窗口类关联的菜单资源名称,如果窗口类包含菜单,该成员指向菜单资源的名称或标识符。

MAKEINTRESOURCEW是一个宏,用于将整数资源标识符转换为字符串资源标识符,与⑤一致;其原型为:

LPWSTR MAKEINTRESOURCEW(WORD wInteger);

参数wInteger为资源标识符的整数值,转换后的字符串资源标识符,类型为 LPWSTR

通过设置 wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_WINDOWSPROJECT1);我们将窗口类关联到一个菜单资源,标识符为 IDC_WINDOWSPROJECT1。当创建窗口时,系统会加载并使用该菜单资源,使得窗口可以包含菜单。这个设置使应用程序窗口能够具备菜单栏,从而提供更多的用户交互选项。

⑨设置窗口类名称
 wcex.lpszClassName  = szWindowClass;

这行代码设置了窗口类的名称,标识该窗口类的唯一名称。

lpszClassName成员:

类型:LPCWSTR
作用:指定窗口类的名称这个名称用于在后续的窗口创建中标识该窗口类。

szWindowClass是一个全局变量,用于存储窗口类的名称。在初始化窗口类时,通过将 szWindowClass 的值赋给 wcex.lpszClassName,注册该窗口类的名称。

类型:WCHAR 数组
定义:WCHAR szWindowClass[MAX_LOADSTRING]; 是一个用于存储窗口类名称的字符数组。
作用:存储窗口类的名称字符串,这个名称在调用 CreateWindow 或 CreateWindowEx 函数时用于标识窗口类。
总结:

通过设置 wcex.lpszClassName = szWindowClass;可以为窗口类指定了一个唯一名称,这在注册和创建窗口时非常重要,因为它标识了窗口类的类型,使得系统能够正确地创建和管理该类窗口。

⑩设置小图标
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

这行代码为窗口类设置了一个小图标,用于任务栏和窗口左上角的小图标。

函数原型为:

HICON LoadIcon(HINSTANCE hInstance, LPCTSTR lpIconName);

hInstance:应用程序实例句柄。用于标识图标资源所在的模块。 lpIconName:图标资源的名称或标识符。可以是一个字符串或使用 MAKEINTRESOURCE 宏定义的整数值。

此处与hIcon成员的设置一致笔者就不再多做赘述了。

hIconSmhIcon 都是用来为窗口类指定图标的成员变量,但它们有不同的用途和显示位置

hIcon:指定窗口类的主图标。这通常是一个较大的图标,用于窗口的标题栏和任务切换界面(如 Alt+Tab 切换窗口时显示的图标)。
hIconSm:指定窗口类的小图标。这通常是一个较小的图标,用于任务栏和窗口左上角的小图标。

注册窗口类

最后,调用 RegisterClassExW 函数来注册窗口类,并返回该函数的结果。

return RegisterClassExW(&wcex);
RegisterClassExW函数原型
ATOM RegisterClassExW(const WNDCLASSEXW *lpwcx);

lpwcx:指向 WNDCLASSEX 结构的指针,包含窗口类的配置信息。

返回值

  • 成功时返回一个唯一的类原子(ATOM)值,表示已注册的窗口类。

  • 失败时返回零。可以调用 GetLastError 函数获取扩展错误信息。

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

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

相关文章

本地快速部署 SuperSonic

本地快速部署 SuperSonic 0. 引言1. 本地快速部署 supersonic2. 访问 supersonic3. 支持的数据库4. github 地址 0. 引言 SuperSonic融合Chat BI(powered by LLM)和Headless BI(powered by 语义层)打造新一代的BI平台。这种融合确…

Python 数据可视化 散点图

Python 数据可视化 散点图 import matplotlib.pyplot as plt import numpy as npdef plot_scatter(ref_info_dict, test_info_dict):# 绘制散点图,ref横,test纵plt.figure(figsize(80, 48))n 0# scatter_header_list [peak_insert_size, median_insert…

如何实现埋点日志精准监控

作者 | 张小七 导读 日志中台承载了百度千亿量级PV的埋点流量,如何对这些流量进行准确监控,并支持个性化字段的抽取、下钻,是日志中台的一大难题。本文简单介绍了日志中台的基本概念及实时流架构,并基于此深入讲解了低成本实现可扩…

【调试笔记-20240618-Windows- Tauri 调试中关闭自动重构的功能】

调试笔记-系列文章目录 调试笔记-20240618-Windows- Tauri 调试中关闭自动重构的功能 文章目录 调试笔记-系列文章目录调试笔记-20240618-Windows- Tauri 调试中关闭自动重构的功能 前言一、调试环境操作系统:Windows 10 专业版调试环境调试目标 二、调试步骤搜索相…

【CSS in Depth2精译】1.1.2 行内样式~1.1.3 选择器的优先级

文章目录 1.1.2 行内样式1.1.3 选择器的优先级1.1.3.1 优先级的写法1.1.3.2 关于优先级的思考 1.1.2 行内样式 如果无法通过样式表来源规则解决样式冲突,浏览器则会考察它们是否通过 行内样式 作用于该元素。当使用 HTML 的 style 属性声明样式时,该样式…

kaggle notebook和jupyter notebook读取csv

kaggle本地比赛用打开notebook的示例代码可以获取当前比赛的文件数据路径,进而后续直接复制读取 jupyter notebook读取csv 直接下载数据集到电脑上,并用本地路径读取就行。

ElasticSearch学习篇13_《检索技术核心20讲》进阶篇之LSM树

背景 学习极客实践课程《检索技术核心20讲》https://time.geekbang.org/column/article/215243,文档形式记录笔记。 内容 磁盘和内存数据读取特点 工业界中数据量往往很庞大,比如数据无法全部加载进内存,无法支持索引的高效实时更新&…

QT day04

一、思维导图 二、登录界面优化 代码: 界面: *{background-color: rgb(255, 255, 255); }QFrame#frame{border-image: url(:/Logo/shanChuan.jpg);border-radius:15px; }#frame_2{background-color: rgba(110, 110, 110, 120);border-radius:15px; }Q…

ionic 项目通过 android studio 打开报错 capacitor.settings.gradle 文件不存在

问题出现 原因分析 在程序相应的目录上面,没有找到对应的配置文件,但是这个文件不是我们自己生成的,而是通过 ionic 编译之后生成。 处理方案 先执行 ionic build,将 ionic 项目打包出来然后执行 npx cap sync 再使用 Android…

【小白专用 已验证24.6.18】C# SqlSugar操作MySQL数据库实现增删改查

【小白专用24.6.18】C# SqlSugar:连接数据库实现简单的,增、删、改、查-CSDN博客 SqlSugar .Net ORM 5.X 官网 、文档、教程 - SqlSugar 5x - .NET果糖网 SqlSugar项目创建 通过NuGet包管理器搜索SqlSugar(MySql还要安装MySql.Data、Newton…

C++ | Leetcode C++题解之第165题比较版本号

题目&#xff1a; 题解&#xff1a; class Solution { public:int compareVersion(string version1, string version2) {int n version1.length(), m version2.length();int i 0, j 0;while (i < n || j < m) {long long x 0;for (; i < n && version1[…

HTML+CSS+PHP实现网页留言板功能(需要创建数据库)

话说前头&#xff0c;我这方面很菜滴。这是我网页作业的一部分。 1.body部分效果展示&#xff08;不包括footer&#xff09; 2、代码 2.1 leaving.php&#xff08;看到的网页&#xff09; <!DOCTYPE html> <html lang"en"> <head> <met…

Flask之模板

前言&#xff1a;本博客仅作记录学习使用&#xff0c;部分图片出自网络&#xff0c;如有侵犯您的权益&#xff0c;请联系删除 目录 一、模板的基本用法 1.1、创建模板 1.2、模板语法 1.3、渲染模板 二、模板辅助工具 2.1、上下文 2.2、全局对象 2.3、过滤器 2.4、测试…

低市值Pow赛道解析,探寻百倍潜力项目

随着铭文的火爆出圈&#xff0c;比特币减半的到来&#xff0c;关于Pow赛道的讨论也在变得火热&#xff0c;不少投资机构都将Pow赛道作为2024年分析的重点。Pow赛道又来已久&#xff0c;不少项目的市值都超过10亿美元&#xff0c;而对于大多数投资者来说&#xff0c;低市值高回报…

Mp3文件结构全解析(一)

Mp3文件结构全解析(一) MP3 文件是由帧(frame)构成的&#xff0c;帧是MP3 文件最小的组成单位。MP3的全称应为MPEG1 Layer-3 音频 文件&#xff0c;MPEG(Moving Picture Experts Group) 在汉语中译为活动图像专家组&#xff0c;特指活动影音压缩标准&#xff0c;MPEG 音频文件…

Spring事务 和 事务传播机制

这里的 事务 和之前 MySQL的事务 一样&#xff0c;都是表示将⼀组操作封装成⼀个执⾏单元&#xff08;封装到⼀起&#xff09;&#xff0c;要么全部成功&#xff0c;要么全部失败。 Spring 中事务的实现 1. 编程式事务&#xff08;手动档&#xff09;。 package com.example.…

图论之岛屿系列

图论之岛屿系列 形成模板进行学习&#xff0c;加快学习效率 深度优先遍历 # 可以直接改原始grid的采用直接改的方案来完成修改&#xff0c;减少了内存开支 def dfs(self, grid, i, j):if i < 0 or j < 0 or i > len(grid) or j > len(grid[0]) or grid[i][j] &…

无引擎底层游戏开发(1):EasyX图形库引入 + 跟随鼠标移动的小球

来自bilibili up主的Voidmatrix的视频教程&#xff1a;【从零开始的C游戏开发】 一、图形库引入 EasyX在国内文档最多&#xff0c;而且功能函数齐全&#xff0c;最适合入门。 环境配置&#xff1a;vs2022 &#xff08;官网下载免费版&#xff09; 百度搜EasyX官方&#xff0…

AI搜索工具,提升你的工作效率

当我们需要查询某个内容的时候&#xff0c;除了可以通过搜索引擎来查找&#xff0c;还可以通过AI搜索工具来查找。AI搜索工具会智能的从网络信息中查找答案并整理后给我们结果。除了搜索结果&#xff0c;AI搜索工具还可以用来帮我们创作内容&#xff0c;比如你需要写一篇文章&a…

【博弈】843. 猜猜这个单词

本题涉及知识点 博弈 LeetCode843. 猜猜这个单词 给你一个由 不同 字符串组成的单词列表 words &#xff0c;其中 words[i] 长度均为 6 。words 中的一个单词将被选作秘密单词 secret 。 另给你一个辅助对象 Master &#xff0c;你可以调用 Master.guess(word) 来猜单词&…