MFC程序设计(四)窗口创建机制

news2025/1/27 23:01:36

钩子函数

钩子属于win32技术,具有优先勾取消息的权利:当一个消息产生时,钩子勾取消息进行处理,然后消息才送回程序

接下来以一个勾取窗口创建消息的钩子为例进行讲解

钩子类型有键盘钩子,鼠标钩子,WH_CBT钩子等等。钩子只勾取自己类型的消息,如WH_CBT钩子只勾取窗口创建的消息

钩子执行过程:钩子只勾取指定应用程序指定线程且属于自己类型的消息,然后触发钩子处理函数。当应用程序实例句柄为空时,则勾取所有应用程序的消息。当线程ID为空时,则勾取指定应用程序的线程的消息

钩子处理函数:钩子码的值取决于钩子类型,每种类型都有它自己唯一的特征钩子码

该函数常常与钩子函数配合使用,通过第二个参数的值可以更改指定窗口的窗口处理函数或者窗口风格等等。

如上图,第二个参数值为GWLP_WNDPROC意味着该函数用于更改窗口处理函数

窗口创建过程

首先创建一个MFC窗口

这是我们上文写的MFC程序所涉及的类

接下来我们通过断点调试来观察窗口是怎么建立的

现在我们进入函数内部,观察Create的执行过程

CMyFrameWnd* pFrame = new CMyFrameWnd;
pFrame->Create(NULL, "MFCCreate")//函数内部this为pFrame(自己new框架类对象地址)。参数1类名称 为lpszClassName,即窗口类名称。接下来注意NULL的动向
{
  //当菜单不为空时
  HINSTANCE hInst = AfxFindResourceHandle(lpszMenuName, ATL_RT_MENU);
  ::LoadMenu(hInst, lpszMenuName)//加载菜单		
  this->m_strTitle = lpszWindowName;//框架类成员保存标题名

  //当菜单为空时
  CreateEx(..., NULL,...)//创建菜单。此时的NULL便是最开始Create的NULL,函数内部this为pFrame
  {
    CREATESTRUCT cs;//该结构体共有十二个成员,分别表示窗口的十二个属性,对应CreateEx的十二个参数
    cs.lpszClass = NULL;//此处复制存在问题,但下面将更改正确
    ....
    ....
    cs.hInstance = AfxGetInstanceHandle();//获取应用程序实例句柄

    this->PreCreateWindow(cs)//注册窗口类并对cs中为NULL的成员重新赋值
    {
      AfxDeferRegisterClass(...)//注册窗口类
      {
        WNDCLASS wndcls;//该窗口类共有十个成员
	    ...//窗口类成员赋值。但此时并没有赋值完全,而是在后续慢慢赋值
	    wndcls.lpfnWndProc = DefWindowProc;//此处为默认窗口处理函数,下面的钩子处理函数将更改我们自己的窗口处理函数
        ...//赋值剩余的窗口类成员
        _AfxRegisterWithIcon(&wndcls, "AfxFrameOrView100sd"..)
        {
          &wndcls->lpszClassName = "AfxFrameOrView100sd";//赋值最后的窗口类名称
          ::RegisterClass(&wndcls)//注册窗口类
          //此时仍未修改窗口处理函数
        }
      }
     }
 
    AfxHookWindowCreate(pFrame)
    {
      _AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData();//获取全局变量&ccc(当前程序线程信息)
       ::SetWindowsHookEx(WH_CBT,_AfxCbtFilterHook,...);//利用Win32的API函数,埋下一个类型为WH_CBT的钩子
       pThreadState->m_pWndInit = pFrame;//将自己new的框架类对象pFrame保存到全局变量ccc的一个成员中。
    }
    ::CreateWindowEx(...);//创建窗口,此函数一旦执行成功,立即转到钩子处理函数。
  }
}

//钩子处理函数,系统自动调取 
//该函数用于关联窗口句柄和框架类对象
_AfxCbtFilterHook(.wParam.)//wParam:创建的窗口的句柄
{
  _AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData();//获取&ccc
  CWnd* pWndInit = pThreadState->m_pWndInit;//获取pFrame===pWndInit
  HWND hWnd = (HWND)wParam;//刚刚创建成功的框架窗口句柄
  pWndInit->Attach(hWnd)//使pFrame与wParam建立联系
  {
    CHandleMap* pMap = afxMapHWND(TRUE)//pMap为映射类对象地址
    {
      AFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState();//获取&bbb
      pState->m_pmapHWND = new CHandleMap(..); //new了一个映射类对象,并将对象地址保存到bbb的一个成员中
      return pState->m_pmapHWND;//返回映射类对象地址
    }
    pMap->SetPermanent(this->m_hWnd = hWnd, pFrame)//函数内部this为pMap
    {
      m_permanentMap[hWnd] = pFrame;//已知句柄,获取pFrame
    }
  }
  (WNDPROC)SetWindowLongPtr(hWnd, GWLP_WNDPROC,AfxWndProc);//将默认窗口处理函数更改为AfxWndProc(真正的窗口处理函数)
}

MFC是由C++封装编写的,根据C++的思想,窗口类对象是可以代表窗口的,但MFC的本质是Win32,在Windows中,只有窗口句柄才能代表窗口,这就形成了一个矛盾。只有通过窗口句柄关联类对象,类对象才能真正的代表窗口,而这就是_AfxCbtFilterHook钩子处理函数所完成的

窗口处理函数

接前文,钩子函数勾取窗口创建消息以后,跳转到真正的窗口处理函数中。现我们通过添加一个WM_PAINT消息观察该消息处理时是不是真的在真正的窗口处理函数中处理

在上图中自定义了窗口处理函数,但最后返回父类虚函数。这是因为我们为了在MFC库收到WM_CREATE消息时,调用我们自己定义的函数,而其他无关消息交给父类虚函数作做默认消息处理

运行程序以后,我们发现在窗口出现前, 程序先弹窗了我们定义的弹窗,然后再弹出窗口

 

此时就存在了一个疑问:在上文中,我们发现真正的窗口处理函数是AfxWndProc,但此处却调用了我们自定义的窗口处理函数

通过调用堆栈我们发现,真正的窗口处理函数AfxWndProc调用了我们自定义的窗口处理函数

//真正的窗口处理函数
//以WM_CREATE消息为例,捎带想着点WM_PAINT消息
AfxWndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)//我们自行调试时,注意uMsg的值,WM_CREATE的值为1
{
  CWnd* pWnd = CWnd::FromHandlePermanent(hWnd)//通过窗口句柄返回框架类对象
  {
    CHandleMap* pMap = afxMapHWND()
    {
      AFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState();//获取&bbb
      return pState->m_pmapHWND;//返回之前保存在bbb中的映射类地址 
    }
    pWnd = pMap->LookupPermanent(hWnd)//函数内部this为pMap
    {
      return m_permanentMap[hWnd];//返回pFrame
    }
  }  

  

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

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

相关文章

【JavaEE进阶】Spring留言板实现

目录 🎍预期结果 🍀前端代码 🎄约定前后端交互接口 🚩需求分析 🚩接口定义 🌳实现服务器端代码 🚩lombok介绍 🚩代码实现 🌴运行测试 🎄前端代码实…

Unity开发一个单人FPS游戏的教程总结

这个系列的前几篇文章介绍了如何从头开始用Unity开发一个FPS游戏,感兴趣的朋友可以回顾一下。这个系列的文章如下: Unity开发一个FPS游戏_unity 模仿开发fps 游戏-CSDN博客 Unity开发一个FPS游戏之二_unity 模仿开发fps 游戏-CSDN博客 Unity开发一个F…

论文速读|Is Cosine-Similarity of Embeddings Really About Similarity?WWW24

论文地址: https://arxiv.org/abs/2403.05440 https://dl.acm.org/doi/abs/10.1145/3589335.3651526 bib引用: inproceedings{Steck_2024, series{WWW ’24},title{Is Cosine-Similarity of Embeddings Really About Similarity?},url{http://dx.doi.o…

71.在 Vue 3 中使用 OpenLayers 实现按住 Shift 拖拽、旋转和缩放效果

前言 在前端开发中,地图功能是一个常见的需求。OpenLayers 是一个强大的开源地图库,支持多种地图源和交互操作。本文将介绍如何在 Vue 3 中集成 OpenLayers,并实现按住 Shift 键拖拽、旋转和缩放地图的效果。 实现效果 按住 Shift 键&#…

PyQt6医疗多模态大语言模型(MLLM)实用系统框架构建初探(上.文章部分)

一、引言 1.1 研究背景与意义 在数字化时代,医疗行业正经历着深刻的变革,智能化技术的应用为其带来了前所未有的发展机遇。随着医疗数据的指数级增长,传统的医疗诊断和治疗方式逐渐难以满足现代医疗的需求。据统计,全球医疗数据量预计每年以 48% 的速度增长,到 2025 年将…

250125-package

1. 定义 包就是文件夹,作用是在大型项目中,避免不同人的编写的java文件出现同名进而导致报错;想象一个场景,在一个根目录中,每一个人都有自己的一个java文件夹,他可以将自己编写的文件放在该文件夹里&…

FastExcel的使用

前言 FastExcel 是一款基于 Java 的开源库,旨在提供快速、简洁且能解决大文件内存溢出问题的 Excel 处理工具。它兼容 EasyExcel,提供性能优化、bug 修复,并新增了如读取指定行数和将 Excel 转换为 PDF 的功能。 FastExcel 的主要功能 高性…

Redis实战(黑马点评)——关于缓存(缓存更新策略、缓存穿透、缓存雪崩、缓存击穿、Redis工具)

redis实现查询缓存的业务逻辑 service层实现 Overridepublic Result queryById(Long id) {String key CACHE_SHOP_KEY id;// 现查询redis内有没有数据String shopJson (String) redisTemplate.opsForValue().get(key);if(StrUtil.isNotBlank(shopJson)){ // 如果redis的数…

python3+TensorFlow 2.x(三)手写数字识别

目录 代码实现 模型解析: 1、加载 MNIST 数据集: 2、数据预处理: 3、构建神经网络模型: 4、编译模型: 5、训练模型: 6、评估模型: 7、预测和可视化结果: 输出结果&#xff…

基础项目——扫雷(c++)

目录 前言一、环境配置二、基础框架三、关闭事件四、资源加载五、初始地图六、常量定义七、地图随机八、点击排雷九、格子类化十、 地图类化十一、 接口优化十二、 文件拆分十三、游戏重开 前言 各位小伙伴们,这期我们一起学习出贪吃蛇以外另一个基础的项目——扫雷…

[操作系统] 深入进程地址空间

程序地址空间回顾 在C语言学习的时,对程序的函数、变量、代码等数据的存储有一个大致的轮廓。在语言层面上存储的地方叫做程序地址空间,不同类型的数据有着不同的存储地址。 下图为程序地址空间的存储分布和和特性: 使用以下代码来验证一下…

OpenCV:图像处理中的低通滤波

目录 简述 什么是低通滤波? 各种滤波器简介与实现 方盒滤波 均值滤波 中值滤波 高斯滤波 双边滤波 各种滤波的对比与应用场景 相关阅读 OpenCV基础:图像变换-CSDN博客 OpenCV:图像滤波、卷积与卷积核-CSDN博客 简述 低通滤波是一…

32、【OS】【Nuttx】OSTest分析(1):stdio测试(二)

背景 接上篇wiki 31、【OS】【Nuttx】OSTest分析(1):stdio测试(一) 继续stdio测试的分析,上篇讲到标准IO端口初始化,单从测试内容来说其实很简单,没啥可分析的,但这几篇…

OpenAI掀桌子!免费版ChatGPT,提供o3-mini模型!

逆天免费用 今天凌晨,OpenAI联合创始人兼首席执行官Sam Altman宣布了一个大消息——免费版ChatGPT,将提供o3-mini模型! 网页们纷纷不淡定了 看来OpenAI,这o3-mini还没正式上线呢,就免费开放使用了。 不过还是要感谢…

redis离线安装部署详解(包括一键启动)

像上文一样 因为在学习的过程中没有查到一个详细的离线部署方案 所以在自己学习之后想要自己写一个文章 希望可以帮助后续学习redis离线部署的朋友少走一线弯路 首先就是下载安装包 可以自己在本地下载再传到机器上(通过xftp或lrzsz都可) http://d…

图论汇总1

1.图论理论基础 图的基本概念 二维坐标中,两点可以连成线,多个点连成的线就构成了图。 当然图也可以就一个节点,甚至没有节点(空图) 图的种类 整体上一般分为 有向图 和 无向图。 有向图是指 图中边是有方向的&a…

小利特惠源码/生活缴费/电话费/油卡燃气/等充值业务类源码附带承兑系统

全新首发小利特惠/生活缴费/电话费/油卡燃气/等充值业务类源码附带U商承兑系统 安装教程如下 图片:

ESMC-600M蛋白质语言模型本地部署攻略

前言 之前介绍了ESMC-6B模型的网络接口调用方法,但申请token比较慢,有网友问能不能出一个本地部署ESMC小模型的攻略,遂有本文。 其实本地部署并不复杂,官方github上面也比较清楚了。 操作过程 环境配置:CUDA 12.1、…

Java 实现Excel转HTML、或HTML转Excel

Excel是一种电子表格格式,广泛用于数据处理和分析,而HTM则是一种用于创建网页的标记语言。虽然两者在用途上存在差异,但有时我们需要将数据从一种格式转换为另一种格式,以便更好地利用和展示数据。本文将介绍如何通过 Java 实现 E…

Ubuntu20.04 运行 PL-VIO

文章目录 运行后不知为何没有线特征 运行后不知为何没有线特征