MFC之底层窗口实现01(包括windows窗口消息机制)

2023-11-07

1 MFC需要了解的相关概念

  • 1) SDK和API
    SDK: 软件开发工具包(Software Development Kit),一般都是一些被软件工程师用于为特定的软件包、软件框架、硬件平台、操作系统等建立应用软件的开发工具的集合,也称第三方工具包。
    API函数: Windows操作系统提供给应用程序编程的接口(Application Programming Interface)。Windows应用程序API函数是通过C语言实现的,所有主要的 Windows 函数都在 Windows.h 头文件中进行了声明。Windows 操作系统提供了 1000 多种 API函数。Windows前的W不区分大小写。
  • 2) 窗口和句柄
    窗口是 Windows 应用程序中一个非常重要的元素,一个 Windows 应用程序至少要有一个窗口,称为主窗口。窗口是屏幕上的一块矩形区域,是 Windows 应用程序与用户进行交互的接口。利用窗口可以接收用户的输入、以及显示输出。一个应用程序窗口通常都包含标题栏、菜单栏、系统菜单、最小化框、最大化框、 可调边框,有的还有滚动条。如下图:
    在这里插入图片描述
    窗口可以分为客户区和非客户区, 如上图。 客户区是窗口的一部分, 应用程序通常在客户区中显示文字或者绘制图形。标题栏、 菜单栏、 系统菜单、 最小化框和最大化框、 可调边框统称为窗口的非客户区, 它们由 Windows 系统来管理, 而应用程序则主要管理客户区的外观及操作。
    窗口可以有一个父窗口, 有父窗口的窗口称为子窗口。除了上图所示类型的窗口外, 对话框和消息框也是一种窗口。 在对话框上通常还包含许多子窗口, 这些子窗口的形式有按钮、 单选按钮、 复选框、 组框、 文本编辑框等。
    在 Windows 应用程序中, 窗口是通过窗口句柄( HWND) 来标识的。 我们要对某个窗口进行操作, 首先就要得到这个窗口的句柄。
    句柄( HANDLE) 是 Windows 程序中一个重要的概念, 使用也非常频繁。 在 Windows 程序中, 有各种各样的资源( 窗口、 图标、光标,画刷等), 系统在创建这些资源时会为它们分配内存, 并返回标识这些资源的标识号, 即句柄。 在后面的内容中我们还会看到图标句柄( HICON)、 光标句柄( HCURSOR) 和画刷句柄( HBRUSH)。或者学过linux的都知道,句柄等同于文件描述符的作用。
  • 3)消息与消息队列
    Windows 程序设计是一种完全不同于传统的 DOS 方式的程序设计方法。它是一种事件驱动方式的程序设计模式,主要是基于消息的。每一个 Windows 应用程序开始执行后, 系统都会为该程序创建一个消息队列, 这个消息队列用来存放该程序创建的窗口的消息。
    例如,当用户在窗口中画图的时候,按下鼠标左键,此时,操作系统会感知到这一事件(注意,并非是应用程序先捕获,而是操作系统先捕获,然后添加到消息队列再给回应用程序),于是将这个事件包装成一个消息,投递到应用程序的消息队列中,等待应用程序的处理。
    然后应用程序通过一个消息循环不断地从消息队列中取出消息,并进行响应。
    在这个处理过程中,操作系统也会给应用程序“ 发送消息”。所谓“ 发送消息”,实际上是操作系统调用程序中一个专门负责处理消息的函数,这个函数称为窗口过程,即窗口过程就是回调函数。
    再次强调,按下应用程序的按钮后,消息首先被操作系统捕获,而不是应用程序本身先捕获。
    在这里插入图片描述
  • 4)WinMain函数
    当Windows操作系统启动一个程序时,它调用的就是该程序的WinMain函数( 实际是由插入到可执行文件中的启动代码调用的)。WinMain是Windows程序的入口点函数,与DOS程序的入口点函数main的作用相同,当WinMain 函数结束或返回时,Windows应用程序结束,即与DOS的main函数返回一样代表进程结束。

2 Windows 编程模型

一个完整的Win32程序(#include <windows.h>),该程序实现的功能是创建一个窗口,并在该窗口中响应键盘及鼠标消息,程序的实现步骤为:

//1、设计窗口
//2、注册窗口
//3、创建窗口
//4、显示和更新
//5、通过循环取消息
//6、处理消息 (窗口过程)

本人软件为VS2017。

  • 1) 项目的创建。VS2015是没有桌面桌面应用程序,需要选择Win32项目。
    在这里插入图片描述
  • 2)然后将.cpp改成.c后缀,否则会出现类型转换失败,因为C++类型检查严谨,不想浪费时间的就直接改后缀。
  • 3)然后将自动创建的文件里面的代码全部删除,将下面代码复制即可。

3 案例

代码注释已经非常详细,并且对照上面的消息循环图理解即可。本篇案例只是为了让大家了解MFC的底层消息处理,平时已经很少这样写代码,一般都是直接使用Qt或者MFC开发了。


#include <windows.h> //底层实现窗口 的头文件

//6处理窗口过程

//CALLBACK  代表__stdcall 参数的传递顺序:从右到左 以此入栈,并且在函数返回前 清空堆栈
LRESULT CALLBACK WindowProc(
	HWND hwnd, //消息所属的窗口句柄
	UINT uMsg, //具体消息名称  WM_XXXX 消息名
	WPARAM wParam, //键盘附加消息
	LPARAM lParam  //鼠标附加消息
)
{
	switch (uMsg)
	{
	case WM_CLOSE:
		//所有xxxWindow为结尾的方法,都不会进入到消息队列中,而是直接执行。即底层流程图直接走窗口过程。
		DestroyWindow(hwnd); //DestroyWindow 发送另一个消息 WM_DESTROY
		break;
	case  WM_DESTROY:
		PostQuitMessage(0);/* 使下面的while循环变成FALSE退出应用程序 */
		break;
	case WM_LBUTTONDOWN: //鼠标左键按下
	{
		int xPos = LOWORD(lParam);
		int yPos = HIWORD(lParam);

		char buf[1024];
		wsprintf(buf, TEXT("x = %d,y = %d"), xPos, yPos);

		MessageBox(hwnd, buf, TEXT("鼠标左键按下"), MB_OK);

		break;
	}
	case WM_KEYDOWN: //键盘
		MessageBox(hwnd, TEXT("键盘按下"), TEXT("键盘按下"), MB_OK);
		break;

	case WM_PAINT: //绘图
	{
		PAINTSTRUCT ps; //绘图结构体
		HDC hdc = BeginPaint(hwnd, &ps);

		TextOut(hdc, 100, 100, TEXT("HELLO"), strlen("HELLO"));

		EndPaint(hwnd, &ps);
	}

	break;
	}


	//返回值用默认处理方式
	return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

//程序入口函数
//WINAPI 代表__stdcall 参数的传递顺序:从右到左 以此入栈,并且在函数返回前 清空堆栈
int WINAPI WinMain(
	HINSTANCE hInstance,		//应用程序实例句柄 
	HINSTANCE hPrevInstance,	//上一个应用程序句柄,在win32环境下,参数一般为NULL,不起作用了
	LPSTR lpCmdLine,			//是一个以空终止的字符串, 指定传递给应用程序的命令行参数,相当于C或C++中的main函数中的参数char *argv[] 
	int nShowCmd)				//表示一个窗口的显示,表示它是要最大化显示、最小化显示、正常大小显示还是隐藏显示。
{

	//1、设计窗口
	//2、注册窗口
	//3、创建窗口
	//4、显示和更新
	//5、通过循环取消息
	//6、处理消息 (窗口过程)

	//1、设计窗口
	WNDCLASS wc;
	wc.cbClsExtra = 0; //类的额外的内存 
	wc.cbWndExtra = 0; //窗口额外的内存
	wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);	//设置背景
	wc.hCursor = LoadCursor(NULL, IDC_HAND);				//设置光标,如果第一个参数为NULL,代表使用系统提供的光标
	wc.hIcon = LoadIcon(NULL, IDI_ERROR);					//图标,如果第一个参数为NULL,代表使用系统提供的光标
	wc.hInstance = hInstance;								//应用程序实例句柄  传入WinMain中的形参即可
	wc.lpfnWndProc = WindowProc;							//窗口过程即回调函数  
	wc.lpszClassName = TEXT("WIN");							//指定窗口类名称
	wc.lpszMenuName = NULL;									//菜单名称
	wc.style = 0;											//显示风格 0代表默认风格

	//2、注册窗口类
	RegisterClass(&wc);

	//3、创建窗口
	/*
	lpClassName,  类名
	lpWindowName, 标题名
	dwStyle,  风格(宏),这里使用常用的WS_OVERLAPPEDWINDOW
	x,  显示坐标,CW_USEDEFAULT,默认值
	y,
	nWidth, 宽高
	nHeight,
	hWndParent,  父窗口,传NULL即可
	hMenu,  菜单,NULL
	hInstance,  实例句柄,hInstance
	lpParam) 附加值,NULL
	*/
	HWND hwnd = CreateWindow(
		wc.lpszClassName, 
		TEXT("WINDOWS"), 
		WS_OVERLAPPEDWINDOW, 
		CW_USEDEFAULT, 
		CW_USEDEFAULT, 
		CW_USEDEFAULT, 
		CW_USEDEFAULT, 
		NULL, 
		NULL, 
		hInstance, 
		NULL);

	//4、 显示和更新
	ShowWindow(hwnd, SW_SHOWNORMAL);
	UpdateWindow(hwnd);

	//5、 通过循环取消息
	/*
	 HWND        hwnd; 主窗口句柄
	 UINT        message; 具体消息名称,int值类型
	 WPARAM      wParam; 附加消息,键盘消息
	 LPARAM      lParam; 附加消息,鼠标消息的左中右键
	 DWORD       time;  消息产生时间
	 POINT       pt;    附加消息,鼠标消息按下的点x,y
	*/
	MSG msg;

	/******************下面过程是等待用户触发消息事件,操作系统捕获后进入while然后消息循环分发,可对比底层流程图理解*************************/

	while (1)
	{
		/*
		  _Out_ LPMSG lpMsg, 消息
		  _In_opt_ HWND hWnd, 捕获窗口 填NULL代表捕获所有的窗口
		  _In_ UINT wMsgFilterMin,  //最小和最大的过滤的消息  一般填入0
		  _In_ UINT wMsgFilterMax)  //填0代表捕获所有消息
		*/
		if (GetMessage(&msg, NULL, 0, 0) == FALSE)
		{
			break;
		}

		//翻译消息,是为了对用户的组合键等复杂操作处理后再分发消息
		TranslateMessage(&msg);

		//不为false则分发消息
		DispatchMessage(&msg);

	}

	return 0;
}

结果:
在这里插入图片描述

按下左键:
在这里插入图片描述

注意:有个别人可能按照下面平时创建项目的方法创建了控制台应用程序的。不想重新创建项目的按照下面解决:
在这里插入图片描述
在这里插入图片描述

这里因为我们是想要理解MFC的底层实现,由于MFC的底层实现是C语言,所以创建.c文件。
在这里插入图片描述

控制台程序转Windows程序解决方法:

  • 1)删除预处理器定义中的_CONSOLE, 改成_WINDOWS。
    在这里插入图片描述

  • 2)打开链接器,子系统选择窗口(/SUBSYSTEM:WINDOWS)。搞定。
    在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

MFC之底层窗口实现01(包括windows窗口消息机制) 的相关文章

  • window系统消失的c盘,实际占用与显示占用相差好多G

    问题 C盘一直显示的红色提醒 我c盘实际占用的空间只有33 1GB 而我的c盘总共大小是59 9GB 显示的剩余大小是1 35GB 也就是说我占用了58 11 和c盘的总文件大小相差了25GB 那么消失的25GB去了哪里 我百度过这个问题
  • fork之后子进程到底复制了父进程什么

    fork之后子进程到底复制了父进程什么 发表于2015 4 3 9 54 08 2161人阅读 分类 操作系统 include
  • MySQL基础(非常全)

    MySQL基础 一 MySQL概述 1 什么是数据库 答 数据的仓库 如 在ATM的示例中我们创建了一个 db 目录 称其为数据库 2 什么是 MySQL Oracle SQLite Access MS SQL Server等 答 他们均是
  • java调优总结

    JVM调优总结 序 几年前写过一篇关于JVM调优的文章 前段时间拿出来看了看 又添加了一些东西 突然发现 基础真的很重要 学习的过程是一个由表及里 再由里及表的过程 呵呵 所谓的 温故而知新 而真正能走完这个轮回的人 也就能称为大牛或专家了
  • 文件管理系统(操作系统)——9张思维导图

    文件管理系统 1 文件管理 1 1 一个文件的逻辑结构 比如一个文本txt文件 又或者Excel文件 在我们用户看来 它是长什么样的 这个就是逻辑结构 几个概念 逻辑结构 就是指在用户看来 单个文件内部的数据应该是如何组织起来的 物理结构
  • redis主从同步,总是显示master_link_status:down的解决方法

    前几天 在修改一台从节点的redis的监听端口后 重启了下redis 发现master link status 很长时间一直都是down状态 查看了redis日志 发现日志里出现很多的 I O error trying to sync wi
  • CentOS 7 关闭网络限制

    1 安装CentOS 7 3操作系统mini版本即可 2 设置关闭Selinux 编辑 etc selinux config vi etc selinux config SELINUX disabled 重启机器 查看selinux状态 s
  • Client-Server问题

    1 实验内容与要求 需要创建客户Client和服务器Server两个进程 它们通过管道进行通信 Client进程派生3个生产者线程 一个管道线程 共享一个20个slots的缓冲区 每个生产者线程随机产生一个数据 打印出来自己的id 进程 线
  • Windows 添加永久静态路由

    route add p 10 10 0 0 mask 255 255 0 0 10 10 6 1 p 参数 p 即 persistent 的意思 p 表示将路由表项永久加入系统注册表
  • CF、SF、OF、ZF标志位

    没学汇编 这种题我真是做一道错一道 OF overflow flag 溢出标志位 溢出标志位 OF 1 表示带符号整数运算时结果发生溢出 对于无符号整数运算 OF没有意义 对于有符号数的溢出判断方式有 1 采用一位符号位 思想为 或 则为溢
  • 程序员的自我修养——链接、装载与库

    1 温故而知新 操作系统概念 北桥 连接高速芯片 系统调用接口 以软件中断的方式提供 如Linux使用0x80号中断作为系统调用接口 多任务系统 进程隔离 设备驱动 直接使用物理内存的弊端 地址空间不隔离 内存使用效率低 程序运行的地址不确
  • 通过源码包*.src.rpm定制开发rpm

    为什么80 的码农都做不了架构师 gt gt gt 1 基本流程 1 下载 安装相应的src rpm包 wget xxx src rpm rpm ivh xxx src rpm 这里的 安装 是指把xxx src rpm中的tar gz p
  • Windows驱动开发(一)第一个驱动程序

    首先我们需要了解 在操作系统中 是分两种权限的 一种是内核态 我们也称为0环 一种是用户态 称之为3环 而在我们的电脑中 驱动程序是运行在内核态的 这意味着和操作系统内核是在同一权限的 而普通的应用程序的权限是最低的 高权限谁不想拥有呢 因
  • OS——文件管理系统磁盘的结构之搞清盘面和柱面

    如上图 每个柱面有三个盘面 即就是3个磁道 柱面可以抽象的理解成是一个套一个的立体的同心圆柱体 例 2019年408真题 磁盘有300个柱面 每个柱面有10个磁道 每个磁道有200个扇区 扇区大小为512B 则磁盘容量 分析 每个柱面有10
  • 由于回车符引起的shell错误

    今天弟弟写shell时出现一个错误 源代码如下 zip r 1 2 执行时出现错误 我也写了相同的语句 发现是可以执行的 把两个文件对比一看 差别在于 出错shell 正确shell 在linux下的回车是 n 在win下面的回车是 r n
  • 如何快速构建CMBD系统-glpi

    脚本后续更新及迭代将由kkitDeploy项目代替 https github com luckman666 kkitdeploy server 请大家持续关注kkitDeploy 一 CMBD系统构建步骤 起初 开发这套CMBD系统是为了帮
  • Linux(12):磁盘配额(Quota)与进阶文件系统管理

    磁盘配额 Quota 的应用与实作 Quota 的一般用途 针对 www server 例如 每个人的网页空间的容量限制 针对 mail server 例如 每个人的邮件空间限制 针对 file server 例如 每个人最大的可用网络硬盘
  • I/O设备模型

    I O设备模型 绝大部分的嵌入式系统都包括一些I O Input Outut 输入 输出 设备 例如仪器上的数据显示屏 工业设备上的串口通信 数据采集设备上用于保存数据的Flash或SD卡 以及网络设备的以太网接口等 I O设备模型框架 R
  • 【操作系统xv6】学习记录4-一级页表与二级页表

    占位
  • 【操作系统xv6】学习记录4-一级页表与二级页表

    占位

随机推荐

  • qt day 5

    实现局域网的网络聊天室功能 1 gt 服务器代码 widget h ifndef WIDGET H define WIDGET H include
  • IDEA安装教程(多图预警)

    简介 关于IDEA的介绍 引用自百度百科 IDEA全称 IntelliJ IDEA 是java编程语言开发的集成环境 IntelliJ在业界被公认为最好的java开发工具 尤其在智能代码助手 代码自动提示 重构 J2EE支持 各类版本工具
  • 集简云简化流程模板,轻松实现工作流程自动化

    集简云平台内置大量自动化流程模板 用户可以在 模板中心 搜索应用名称 选择适合自己的场景 直接使用 本期分享集简云自动化工作流程 模板推荐 模板1 小鹅通新增订单后同步到seatable并更新微伴助手用户信息 集成应用 小鹅通 SeaTab
  • [终端配色方案]

    配色方案 一 Iterm2 设置Color Preferences gt Profiles gt Colors Brighten bold text去掉 选择solarized 选择xterm 256color 二 Iterm2 Shell
  • Restful风格

    文章目录 前言 一 Restful风格是什么 二 Restful风格里面的请求方式 1 Get 2 POST 3 PUT 4 DELETE 这四个在项目接口中分别代表的是查 增 改 删 三 Restful风格的Controller如何实现
  • django静态文件无法访问解决方案

    nginx配置如下 For more information on configuration see Official English Documentation http nginx org en docs Official Russi
  • 开发日记2021-17、20周

    2021 4 19 温习了下观察者模式 学习了状态模式 但是感觉状态模式不是太能把握透彻 代码结构不太一样 理解起来有些偏差 写着写着就陷入到了沉思中 总会忘记要把想法记下来 这里就是草稿就是思路演练场 这里写下的东西不需要完美 只要记录下
  • 【Clion+CubeMX开发STM32】(二)创建自己的工程

    目录 新建工程 修改芯片型号 添加自己的文件 将自己的文件添加Cmake项目 修改CMakeLists template txt 烧录程序 编写 cfg文件 编写 cfg文件 新建工程 打开你的Clion 点击新建工程 在左侧找到STM32
  • 期货开户寻找交易确定性

    1 寻找确定性 都说金融是概率游戏 大家都是说胜率有多少 没有谁敢说行情能100 确定 但傅海棠却提出 在特定情况下 能找到100 确定的行情 他的这个观点也一度引起了广泛的争议 傅海棠说 物极必反 必 是100 不是概率 关键是找到那个
  • Unity3D之sprite动画(Animation)的制作

    实例说明 忍者跑酷的player动画制作 这些都是用Sprite做的动画 在prioject面板里的一组sprite里面点击 之后看属性面板的Sprite Editor对这组Sprite进行编辑 下面先编辑一个idle状态的动画 首先选择第
  • 贝叶斯推断及其互联网应用(一)

    贝叶斯推断及其互联网应用 一 投递人 itwriter 发布于 2011 08 25 14 03 评论 6 有1981人阅读 原文链接 收藏 一年前的这个时候 我正在翻译Paul Graham的 黑客与画家 那本书大部分谈的是技术哲学 但是
  • 二、水平管道中CO2气液两相的流量研究

    水平管道中CO2气液两相的流量研究 3 1 引言 在CCS系统的CO2管道运输过程中 由于传输距离较长且受到管道周围环境的影响 管道中的CO2不可避免的会发生相态的改变 产生气液两相CO2流 因此 本研究基于多传感器系统的测量方法 对水平管
  • android hwcomposer 抓取各个显示图层的raw显示数据

    amlogic 平台 void fill color void vaddr int cnt unsigned int p data p data unsigned int vaddr for int i 0x00 i lt 256 1920
  • 服务器---session理论知识

    1 session理论知识 1 1 session何时创建 1 2 session何时销毁 1 session何时创建 Session 机制 session机制是一种服务器端的机制 用来在无状态的HTTP协议下越过多个请求页面来维持状态和识
  • Mac上Pycharm中安装anaconda的pandas和numpy的方法

    1 点击PyCharm菜单栏下的Preferences 2 选择需要安装的project中的Project Interpreter选项 3 选择一个python版本 如红框1 下面会列出已经安装了的Package 这时点击红框2的anaco
  • 【Mac】Mac下SSH免密登录localhost

    1 背景 问题起因参考 mac下ssh 报错 localhost ssh connect to host localhost port 22 Connection refused 为了在MAC上搭建Hadoop standalone 需要配
  • gtx1050ti最稳定的驱动_更新PC电脑的蓝牙驱动方法

    有时候我们需要更新自己的电脑蓝牙版本使我们在特定环境下更好的使用 下面就来讲讲怎么更新蓝牙版本 一 首先我们要查看自己电脑的蓝牙版本 1 右键点击左下方的开始菜单 找到设备管理器 M 2 点开设备管理器 找到蓝牙并右键属性 并查看驱动程序
  • Vue3 中的 @Options,是做什么的?

    Vue3 中的 Options 是做什么的 Options 是个啥 为什么我的项目中会有 Options 或 Component 啥是 类语法风格的组件 Class Style Component Vue Class Component 更
  • 【Hello mysql】 mysql的复合查询 (重点)

    Mysql专栏 Mysql 本篇博客简介 介绍mysql的复合查询 mysql的复合查询 基本查询回顾 查询工资高于500或岗位为MANAGER的雇员 同时还要满足他们的姓名首字母为大写的J 按照部门号升序而雇员的工资降序排序 使用年薪进行
  • MFC之底层窗口实现01(包括windows窗口消息机制)

    1 MFC需要了解的相关概念 1 SDK和API SDK 软件开发工具包 Software Development Kit 一般都是一些被软件工程师用于为特定的软件包 软件框架 硬件平台 操作系统等建立应用软件的开发工具的集合 也称第三方工