Win32程序与MFC程序构建顺序梳理

Windows程序的生成顺序

Windows窗口的生命周期

初始化操作
  • 从WinMain函数开始,注册窗口;
  • 创建窗口;
    • 调用CreateWindow,为程序建立了一个窗口,作为程序的屏幕
      舞台。CreateWindow产生窗口之后会送出WM_CREATE消息给窗口函数,后者
      于是可以在此时做些初始化操作(例如配置内存、打开文件、设置窗口初始数据等)。
  • 显示刷新窗口
 ShowWindow (hwnd, iCmdShow) ;    //显示窗口
UpdateWindow (hwnd) ;    //刷新窗口
用户交互操作

GetMessage函数用于从消息队列中获取消息,DispatchMessage函数(在Windows USER模块的帮助下)则是将消息分派到相应的窗口函数进行处理。这是Windows编程中常见的一种机制,用于处理用户界面的交互和事件。

WM_QUIT是特定的消息类型,当接收到这个消息时,GetMessage会返回0并结束while循环,进而结束整个程序。
下图为Windows处理用户交互信息的过程:
在这里插入图片描述

关闭窗口

使用者按下系统菜单中的Close命令 -> 系统送出WM_CLOSE消息 -> DefWindowProc处理调用DestroyWindow -> Destroy Window送出WM_DESTROY消息 -> 程序对WM_DESTROY的标准反应是调用PostQuitMessage送出WM_QUIT消息 -> 消息循环中的GetMessage取得,如步骤2,结束消息循环.

MFC程序的生成顺序

通过Windows SDK程序可以得出程序运行的最重要的两部分为WinMain(初始化操作)、WinProcedure(处理信息)

MFC中类的派生关系:CObject->CCmdTarget->CWinThread->CWinApp

准备阶段1

MFC程序中WinMain函数的作用被CWinApp类取代了,它所负责的全部初始化工作和对消息解释及分派都有 CWinApp类的内部函数来完成,但是WinMain仍然存在,并且扮演着驾驭CWinApp的角色。CWinApp中几个最重要的函数如下:

virtual BOOL InitApplication();
virtual BOOL InitInstance();
virtual int Run();

在SDK程序设计中至关重要的主窗口句柄(就是那个hwnd,几乎程序所有有关窗口的操作都必须用到该句柄,它为Windows定位所要输出的信息 的目的窗口),它被存储在CWinThread中名为m_MainWnd的成员变量中,而CWinThread是CWinApp的父类。

准备阶段2

WndProc窗口函数与WinMain一样被变形后由单独生成的类进行了替代,替代它的是名为CFrameWnd的类,该类一般因程序不同而被继承为不同的模样,比较有代表性的一般形态如下:

class CMyFrameWnd : public CFrameWnd
{
public:CMyFrameWND();afx_msg void OnPaint();afx_msg boid OnAbout();DECLARE_MESSAGE_MAP();
};
程序构建及运行
  • 1、设置全局对象
    大量的CWinApp之中的成员变量由于theApp的诞生而进行了配置或被赋初值,因此我们完全可以说theApp这个Application object是整个程序的引爆器。
  • 2、the App配置完成之后,应有WinMain函数处理
    在…\Microsoft Visual Studio\VC98\MFC\SRC目录下可以找到一个名为WinMain.cpp的文件其中体现WinMain主要工作的代码为:
int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPTSTR lpCmdLine, int nCmdShow)
{...CWinApp* pApp = AfxGetApp();// AFX internal initializationif (!AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow))goto InitFailure;if (pApp != NULL && !pApp->InitApplication())goto InitFailure;// Perform specific initializationsif (!pThread->InitInstance()){...};nReturnCode = pThread->Run();}

重点为AfxWinInit函数调用、pApp->InitInstance(); nReturnCode=pApp->run();

  • 首先是AfxWinInit,它隐藏在APPINIT.CPP中,重要代码如下:
BOOL AFXAPI AfxWinInit(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPTSTR lpCmdLine, int nCmdShow)
{	...CWinApp* pApp = AfxGetApp();if (pApp != NULL){// Windows specific initialization (not done if no CWinApp)pApp->m_hInstance = hInstance;pApp->m_hPrevInstance = hPrevInstance;pApp->m_lpCmdLine = lpCmdLine;pApp->m_nCmdShow = nCmdShow;pApp->SetCurrentHandles();}}
  • pApp->InitInstance,CWinApp类中此函数是虚函数,由于程序改写了该函数,所以现在等于调用我们自己的InitInstance,我们的程序也将从这里开始自己主窗口的生命。生成的一个简单程序的这一段代码如下:
BOOL CTestApp::InitInstance()
{...	CMainFrame* pMainFrame = new CMainFrame;//调用了CMainFrame的构造函数...if (!ProcessShellCommand(cmdInfo))return FALSE;m_pMainWnd->ShowWindow(SW_SHOW);    //这两行与SDK程序m_pMainWnd->UpdateWindow();         //极为相似
}
  • CWinApp::Run事实上指向CWinThread::Run,它位于THRDCORE.CPP中,代码如下:
int CWinThread::Run()
{while (bIdle &&!::PeekMessage(&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE)){// call OnIdle while in bIdle stateif (!OnIdle(lIdleCount++))bIdle = FALSE; // assume "no idle" state}// phase2: pump messages while availabledo{// pump message, but quit on WM_QUITif (!PumpMessage())return ExitInstance();// reset "no idle" state after pumping "normal" messageif (IsIdleMessage(&m_msgCur)){bIdle = TRUE;lIdleCount = 0;}} while (::PeekMessage(&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE));}ASSERT(FALSE); // not reachable
}
PumpMessage代码如下:
BOOL CWinThread::PumpMessage()
{ASSERT_VALID(this);if (!::GetMessage(&m_msgCur, NULL, NULL, NULL)){return FALSE;}// process this messageif (m_msgCur.message != WM_KICKIDLE&& !PreTranslateMessage(&m_msgCur)){::TranslateMessage(&m_msgCur);//SDK相似代码::DispatchMessage(&m_msgCur);}return TRUE;
}

MFC程序死亡调用顺序与Win32程序大同小异。
文章主要参考:
http://blog.chinaunix.net/uid-21169302-id-446230.html

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

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

相关文章

新手运行若依项目|若依项目各部分介绍|并修改自己需要的页面

新手运行若依项目|若依项目各部分介绍|并修改自己需要的页面 文章目录 新手运行若依项目|若依项目各部分介绍|并修改自己需要的页面前言IEDA如何运行若依项目若依项目目录简介ruo-yi common工具类ruoyi-framework 框架核心其他部分ruo一admin后台服务通用配置 application.yml数…

关于“Python”的核心知识点整理大全26

目录 10.3.9 决定报告哪些错误 10.4 存储数据 10.4.1 使用 json.dump()和 json.load() number_writer.py number_reader.py 10.4.2 保存和读取用户生成的数据 对于用户生成的数据,使用json保存它们大有裨益,因为如果不以某种方式进行存储&#xf…

小红书kop营销策略有哪些,达人投放总结!

从kol到koc,当今时代产品种草模式,层出不穷。品牌想要跟上市场更新迭代的洪流,就需要时刻了解新型的营销方式。那么对于新型的kop模式你了解多少呢?我们今天就将详细分享小红书kop营销策略有哪些,达人投放总结! 一、什…

低代码工作流,在业务场景下启动流程节点绑定的具体步骤与注意事项

在业务管理的场景下,存在先做了对应的数据管理,后续增加管理的规范度,“在业务数据变化时发起流程”的需求,那么这种情况下就需要在业务管理(列表页、表单)中发起流程,让业务模型使用流程配置&a…

运维开发实践 - 服务网关 - apisix部署

1. Apache Apisix Apache Apisix 是一个动态,实时,高性能的云原生API网关,提供负载均衡,动态上游,灰度发布,服务熔断,身份认证,可观测性等丰富的流量管理功能; 2. 如…

windows10-tdengine的安装及使用

win10-tdengine的安装及使用 一、下载及安装配置1.1 下载安装1.2 配置1.3 关闭防火墙和开放端口1.3.1 关闭防火墙1.3.2 开放6030端口 二、启动及关闭服务2.1 启动tdengine服务2.2 关闭tdengine服务2.2 开机自启动配置 四、可视化工具五、TDengine 命令行(CLI&#x…

VUE中的8种常规通信方式

文章目录 1.props传递数据(父向子)2.$emit触发自定义事件(子向父)3.ref(父子)4.EventBus(兄弟组件)5.parent或root(兄弟组件,有共同祖辈)6.attrs和listeners(…

Chrome2023新版收藏栏UI改回旧版

版本 120.0.6099.109(正式版本)Chrome浏览器菜单新版、旧版的差异 想要将书签、功能内容改回旧版的朋友可以网址栏输入:「chrome://flags」,接着搜寻「Chrome Refresh 2023」。 最后将 Chrome Refresh 2023、Chrome Refresh 2023…

Linux驱动(中断、异步通知):红外对射,并在Qt StatusBus使用指示灯进行显示

本文工作: 1、Linux驱动与应用程序编写:使用了设备树、中断、异步通知知识点,实现了红外对射状态的异步信息提醒。 2、QT程序编写:自定义了一个“文本指示灯”类,并放置在QMainWidget的StatusBus中。 3、C与C混合编程与…

Kotlin 笔记 -- Kotlin 语言特性的理解(一)

函数引用、匿名函数、lambda表达式、inline函数的理解 双冒号对函数进行引用的本质是生成一个函数对象只有函数对象才拥有invoke()方法,而函数是没有这个方法的kotlin中函数有自己的类型,但是函数本身不是对象,因此要引用函数类型就必须通过双…

虚拟机无法进入系统问题

概述 客户在华为云平台上创建了两台虚拟机并部署aarch64 V10 OS,2021-10-28其中一台虚拟机业务出现异常,运维重启虚拟机后系统进不去,左上角光标闪烁,接着重启另一台虚拟机同样起不来,现象一致。 分析 通过分析现场…

【MySQL命令】show slave status\G 超详细全面解释

这个命令是DBA日常运维中常用来查看主从状态的命令,很多备份,监控工具也会使用到该命令监控主从状态是否正常,主从延迟,获取位点信息等。作为常用日常命令,一定要完全理解该命令的输出。今天主要结合 官方文档 和 实际…

Spring01

一、Spring概述 自 2004年 4 月,Spring 1.0 版本正式发布以来,Spring 已经步入到了第 5 个大版本,也就是我们常说的 Spring 5。 Spring的基础是Spring Framework,其功能有: 1、IoC (控制反转),Spring 两大…

没错,数据库就应该跑在 k8s 里

昨天冯老板发了一篇文章探讨了为什么将数据库放入 K8S 中不是一个明智的选择。 如果是四年前有人质疑容器化数据库我觉得还可以 battle 一下,都 2023 年了还有人不能认清这个大势,我就有必要来谈谈我的看法了。 我从 K8s 0.9 版本时就开始做这件事&…

Pelee: A Real-Time Object Detection System on Mobile Devices(CVPR 2019)

文章目录 年三十AbstractIntroductionPeleeNet:一个高效的特征提取网络架构消融实验数据集不同设计选择对性能的影响 在ImageNet ILSVRC 2012上的结果真实设备上的速度 Pelee:实时目标检测系统Overview在VOC 2007上的结果不同设计选择的影响与其他框架的比较真实设备…

Linux下使用HTTP进行数据传输的代码实例

在Linux系统中,HTTP协议是一种广泛使用的应用层协议,用于在网络中传输数据。下面是一个使用Python的requests库在Linux下进行HTTP数据传输的代码实例。 python复制代码 import requests # 发送HTTP GET请求 response requests.get("h…

C++面试宝典第6题:访问数组和联合体元素

题目 阅读下面的代码段,并给出程序的输出。 (1)访问数组元素。 int a[] = {61, 62, 63, 64, 65, 66}; int *p = (int *)(&a + 1); printf("%d, %d\n", *(a + 1), *(p - 1)); (2)访问联合体元素。 union {short i;char x[2]; }a;a.x[0] = 10; a.x[1] = 1; …

YOLOv5改进 | 卷积篇 | SPD-Conv空间深度转换卷积(高效空间编码技术)

一、本文介绍 本文给大家带来的改进内容是SPD-Conv(空间深度转换卷积)技术。SPD-Conv是一种创新的空间编码技术,它通过更有效地处理图像数据来改善深度学习模型的表现。SPD-Conv的基本概念:它是一种将图像空间信息转换为深度信息…

Java_常见算法

一、常见算法 1.1 认识算法 接下来,我们认识一下什么是算法。算法其实是解决某个实际问题的过程和方法。比如百度地图给你规划路径,计算最优路径的过程就需要用到算法。再比如你在抖音上刷视频时,它会根据你的喜好给你推荐你喜欢看的视频&a…

Eolink Apikit 如何进行 Websocket 接口测试?

什么是 websocket ? WebSocket 是 HTML5 下一种新的协议(websocket协议本质上是一个基于 tcp 的协议)。 它实现了浏览器与服务器全双工通信,能更好的节省服务器资源和带宽并达到实时通讯的目的 Websocket 是一个持久化的协议。…