MFC程序的基础文件等介绍
公司的C++代码是用Visual Studio来进行开发的,这样就会用到MFC中的很多基础类文件,比如 STDAFX.H, AFXWIN.H, 会发现诸如 CWinApp, CFrameWnd 之类的,刚开始看不是很理解都是干什么的,现在我们来大概解释一下
1. 在代码中很多cpp文件中,都可以看到这么一行 #include "stdafx.h" => 我们来理解一下 stdafx.h 是干什么用的
所有的MFC头文件都在\MSVC\MFC\INCLUDE中,这些文件在编译时,会耗费大量时间,所以这里设定了Precompiled header. 顾名思义,这个Precompiled header就是把很多.H文件第一次编译后的结果存储起来,等后面再次需要编译这么多.H文件时,就不用再次进行编译,直接从磁盘中把第一次编译的结果取出来即可。 这样做是因为,一个应用程序通常需要不断的进行编译,Windows程序载入的.H文件将会非常巨大但是内容不变,每次载入的内容都是一样的,这样,编译器每次浪费大量的时间去编译它们。为了提高程序运行效率,就有了Precompiled header. => 这里,这个stdafx.h 就是用来作为 Precompile header file, 它里面的内容,其实就只是载入了其他的MFC头文件。
应用程序通常都会准备自己的头STDAFX.H, 我在看公司代码时,发现很多项目中都加上了这个STDAFX.H,里面的内容除了都会有通用的以下几个
#include <afxwin.h> => 这个afxwin.h 是MFC core and standard components
#include <afxext.h> => 这个afxext.h 是MFC extensions
#include <afx......> 这些MFC本身提供的头文件之外,有时候还会有一些我们项目本身写的头文件,这些头文件有一个特点,那就是 are used frequently, but are changed infrequently => 经常要使用,但很少变更
2. AFXWIN.H
AFX前缀是微软MFC一个小组的简称, 微软的Application Framework技术团队,名为AFX小组
Afx*.h是一组MFC的核心头文件,比如:
afxwin.h => 定义MFC的核心和标准组件
afxext.h => 定义MFC的扩展
afxdisp.h => 是MFC自动化支持的类定义头文件
afxdb.h => 是MFC的ODBC类封装
这个文件是MFC的,上面中其实我们也提到了,它是MFC core and standard components. 每一个Windows MFC程序都必须载入它,因为它以及它所载入的文件声明了所有的MFC类.
在这个AFXWIN.H中,有关于afx_msg的定义, 我后来在代码中发现很多地方都用到了这个afx_msg
#define afx_msg //intentional placeholder
#define afx_msg //故意安排一个空位置,也许以后版本会用到 => 这个定义在AFXWIN.H中,这个afxwin.h是MFC Core and standard component, MFC中的一个非常关键的头文件
afx_msg是一个宏,标识是消息映射函数,这个消息映射函数是什么意思呢?
消息映射机制是Windows编程的核心内容. Windows下的应用程序也都是通过消息驱动的机制来进行工作的. 虽然Visual Studio C++的开发环境自带了大量的系统消息处理函数, 但是在我们实际开发过程中,总是难以避免还需要程序员自己来写一些自定义的消息处理函数来满足需求. 而消息映射就是将消息本身(包括特定的消息,命令或通知) 和对应的消息处理函数映射起来.
在Visual Studio中,我们可以通过Class Wizard,也就是类向导来创建一个类,然后它会自动生成代码, 这个在Visual Studio => 菜单栏中的 Project => Class Wizard 来进行
上面这个类向导ClassWizard中的命令和消息基本都可以看做是windows的消息,命令Commands代表命令消息ON_COMMAND, 消息Messages代表窗口消息ON_MESSAGE
我们上面提到的afx_msg就是用来给MFC classwizard作标记的,表示在对应的.cpp文件中classwizard产生的代码应该插入的地方,如果把 afx_msg....等类似的符号删除了,classwizard就会报错。也就是说,你不能再用classwizard来自动生成代码,只能通过手工输入.
3. CWinApp
在MFC的AFXWIN.H中,有一个很重要的类CWinApp, 它的注释信息是 the root of all Windows applications (application base class), 它代表程序本体
CWinApp又继承CWinThread, CWinThread的注释信息是thread base class
在项目代码中,我发现有一个全局变量theAPP的定义,这个theAPP就是这里的CWinAPP对象,代表application object. 每一个应用程序(比如CMyWinApp),继承CWinApp的都应该改写CWinApp::InitInstance()函数
MFC把有着相当固定行为的WinMain内部操作封装在CWinApp中,传统SDK程序WinMain完成的工作,现在由CWinApp的三个函数完成:
Virtual BOOL InitApplication();
Virtual BOOL InitInstance();
Virtual int Run();
这几个函数代码动作都是MFC为了内部管理而做的。一般而言,我们写的应用程序(比如CMyWinApp), 只需要改写CWinApp中的InitInstance,而不需要改写InitApplication和Run. 因为InitInstance这个虚拟函数在CWinApp中就是个空函数,没有任何内建(预设)动作,所以在我们的应用程序(比如CMyWinApp)中一定要进行改写
上面说了 => CWinApp继承自CWinThread, CWinThread中有一个成员变量CWnd* m_pMainWnd, 除此之外,CWinThread中还提供一个虚方法GetMainWnd(), 它返回的也是CWnd*
CWnd* m_pMainWnd => 代表主窗口, 这里m_pMainWnd是一个匈牙利表示法, m_p开头表示该变量为某个类的成员变量,变量类型为某种指针. MainWnd一般表示主框架窗口.
因为CWinApp继承自CWinThread, 所以也就继承了CWinThread的成员变量m_pMainWnd => 所以我在项目代码中,经常能够看到以下代码
theApp.m_pMainWnd 就是得到本程序的主窗口
通常,在Visual Studio C++代码中,我们也会用AfxGetApp()->m_pMainWnd的方式来得到主窗口, 那么,这里的AfxGetApp()又是什么呢
AfxGetApp()是全局的,这个全局函数可以得到当前应用进程的指针,是CWinApp*类型的,通过这个指针可以访问到这个进程中的对象,包括m_pMainWnd
AfxGetApp()返回的这个当前应用程序的CWinApp*类型的进程指针,它是唯一的,比如说你在不同的地方用它给程序传递数据
我们上面提到了,CWinApp继承自CWinThread, 而CWinThread中存在
CWnd* m_pMainWnd
virtual CWnd* GetMainWnd();
所以,在项目代码中,我也经常看到AfxGetApp()->GetMainWnd() 来获取Cwnd指针
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)