MFC源码实战分析(一)——从一个最简MFC程序说开去

深入浅出MFC 书中源码Frame1(C++11) 深入浅出MFC 书中源码Frame1(C++11) MFC.h #include <iostream> class CObject { public: CObject() { std::cout << "CObject Constructor" << std::endl; } ~CObject() { std::cout << "CObject Destructor" << std::endl; } }; class CCmdTarget 阅读详情

偶然翻到以前学MFC时做的笔记,又回想起那段激情燃烧的岁月。当初为了学MFC还是下了一番功夫的,正好最近写文章有些拖延,就把这些笔记整理了一下发上来炒炒冷饭。如果能帮到一两位同好也算是皆大欢喜的事情了。

编译与运行

这是一个最简单的MFC应用程序,我们通过它来学习一些MFC的基础知识。首先新建一个Win32 Application,代码如下:

源代码:

#include <afxwin.h>

class CMyWnd : public CFrameWnd
{
public:
    CMyWnd()
    {
        MessageBox(TEXT("In CMyWnd::CMyWnd"), TEXT("In CMyWnd::CMyWnd"), MB_OK);
        Create(NULL, TEXT("My MFC Window"));
    }
    ~CMyWnd()
    {
        MessageBox(TEXT("In CMyWnd::~CMyWnd"), TEXT("In CMyWnd::~CMyWnd"), MB_OK);
    }
};

class CMyApp : public CWinApp
{
public:
    CMyApp()
    {
        MessageBox(NULL, TEXT("In CMyApp::CMyApp"), TEXT("In CMyApp::CMyApp"), MB_OK);
    }

    BOOL InitInstance();
    BOOL ExitInstance();

    ~CMyApp()
    {
        MessageBox(NULL, TEXT("In CMyApp::~CMyApp"), TEXT("In CMyApp::~CMyApp"), MB_OK);
    }

};

BOOL CMyApp::InitInstance()
{
    MessageBox(NULL, TEXT("InitInstance"), TEXT("InitInstance"), MB_OK);
    CMyWnd *pCMyWnd = new CMyWnd();
    m_pMainWnd = pCMyWnd;
    pCMyWnd->ShowWindow(SW_SHOWNORMAL);
    return TRUE;
}

BOOL CMyApp::ExitInstance()
{
    MessageBox(NULL, TEXT("ExitInstance"), TEXT("ExitInstance"), MB_OK);
    return TRUE;
}

CMyApp theApp;

解决编译、链接过程中的错误

创建代码后,编译链接时提示找不到符号,为此,修改工程项目属性,引入MFC的静态库:
这里写图片描述
编译时,会报MFC静态库中的符号和libcmt中的冲突(其实就是libcmt中的符号重复了),将其忽略即可:
这里写图片描述
这样,就能正常编译了。

程序的组织结构:

全局观:

  1. theApp全局对象创建,CMyWinApp::CMyWinApp及其父类、爷爷类、…、祖宗类的构造函数被调用
  2. 进入WinMain函数,通过CWinApp对象的指针(指向的是全局对象theApp的地址)调用InitInstance,CMyWinApp::InitInstance被调用
  3. 在CMyWinApp::InitInstance中创建CMyWnd对象,触发CMyWnd::CMyWnd调用,在其中完成CreateWindow
  4. CMyWnd创建完后,在CMyWinApp::InitInstance通过指针调用其ShowWindow函数,窗口出现
  5. 窗口关闭后,CMyWnd析构
  6. 程序结束时,CMyWinApp::ExitInstance被调用,CMyWinApp析构

theApp对象与消失的WinMain

  • theApp对应的类是控制整个应用程序的,所以称为CWinApp类,是不可或缺的一个类。而且要运行程序,要将该类实例化。
  • 全局对象的实例化先于WinMain函数,故CMyApp的构造函数以及其父类的构造函数都会被调用(最先被调用的其实是CMyApp::CMyApp(),但在其一开始的位置调用了CWinApp::CWinApp()所以效果上是父类的构造函数先被调用)
    这里写图片描述
  • 其构造函数被调用后,程序进入WinMain函数,在其中(WinMain->AfxWinMain)调用InitInstance。WinMain在MFC框架的源程序里:
    这里写图片描述
    作为验证,我们来探望一下位于appmodul.cpp中的WinMain:
    这里写图片描述
    并且找到AfxWinMain中调用InitInstance中的地方:
    这里写图片描述
    其中,pThread是什么鬼呢?
    这里写图片描述
    答案:pThread是CWinThread类的指针,而CWinThread类是CMyWinApp类的爷爷,族谱在此:
    这里写图片描述
    因此,名正言顺地就把CMyWinApp::InitInstance函数给调用了

CMyApp::InitInstance与CMyWnd的纠葛

创建CMyWnd对象

CMyWinApp::InitInstance是我们自己写的,其中有一句

CMyWnd *pCMyWnd = new CMyWnd(); 

这样就动态创建了CMyWnd的对象,CMyWnd::CMyWnd被调用

创建窗口

而在其中,主要调用了Create方法在内存中创建窗口,而在其中又会调用CreateEx函数,最终调用CreateWindow函数。
这里写图片描述
而CreateWindow后,还需要ShowWindow,这一步在CMyWinApp::InitInstance中完成。至此,窗口创建成功。

窗口关闭后

窗口关闭后,CMyWnd的爷爷CWnd响应了WM_DESTROY消息。响应分成两步:
1. 调用PostQuitMessage退出消息循环:
这里写图片描述
2. 调用PostNcDestroy函数,该函数被CMyWnd的爷爷CFrameWnd重载了,在其中调用delete自杀了
这里写图片描述
这将导致CMyWnd对象被析构:
这里写图片描述

而PostQuitMessage发出的WM_QUIT消息进入消息队列后,导致位于CWinThread中的消息循环结束,调用到它孙子的CMyWnd::ExitInstance:
这里写图片描述
CMyApp::ExitInstance()被调用
这里写图片描述
CMyApp::ExitInstance()被调用后,执行完后续代码后WinMain返回,最后CMyApp析构。
这里写图片描述

其他细节

int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
    _In_ LPTSTR lpCmdLine, int nCmdShow)
{
    ASSERT(hPrevInstance == NULL);

    int nReturnCode = -1;
    CWinThread* pThread = AfxGetThread();
    CWinApp* pApp = AfxGetApp();

    // AFX internal initialization
    if (!AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow)) goto InitFailure;

    // App global initializations (rare)
    if (pApp != NULL && !pApp->InitApplication()) goto InitFailure;

    // Perform specific initializations
    if (!pThread->InitInstance())
    {
        if (pThread->m_pMainWnd != NULL)
        {
            TRACE(traceAppMsg, 0, "Warning: Destroying non-NULL m_pMainWnd\n");
            pThread->m_pMainWnd->DestroyWindow();
        }
        nReturnCode = pThread->ExitInstance();
        goto InitFailure;
    }
    nReturnCode = pThread->Run();

InitFailure:
    AfxWinTerm();
    return nReturnCode;
}

1.InitInstance与InitApplication
这两个函数都是在CWinApp中声明的虚函数,前者负责每个实例都要初始化一次的动作,后者负责一个应用中只需要初始化一次的操作。由于在我们的CMyApp中重载了InitInstance,所以最终调用的是CWinApp::InitApplication和CMyApp::InitInstance

2.CMyWnd构造函数中的Create
由于CMyWnd没有重载Create,故调到的是CFrameWnd::Create,其中会完成菜单资源和程序标题初始化(如果有的话),并调用CreateEx;而CFrameWnd没有重载CreateEx,故调到的是CWnd::CreateEx,该函数中调用了PreCreateWindow,这是一个在CWnd中定义的虚函数,可被子类覆盖,所以调用的是CFrameWnd::PreCreateWindow。之后,会调用AfxHookWindowCreate,这个函数会完成一项很重要的工作,留在第三节中讨论,完成后,调用CreateWindowEx创建窗口。

MFC实现傅里叶变换(附完整源码) 阅读详情

相关推荐

MFC实现产生随机数(附完整源码)

MFC实现产生随机数(附完整源码)

希望我的博客,能帮上你解决学习中工作中所遇到的问题 976

两种方法查看MFC源代码

两种方法查看MFC源代码,使用mfc.bsc和VAX插件

无幻 2万+

MFC Windows 程序设计[160]之频谱分析(附源码)

MFC是微软公司提供的一个类库(class libraries),用以减少应用程序开发人员的工作量。其中包含大量Windows句柄封装类和很多Windows的内建控件和组件的封装类。有很多初学MFC的小伙伴们都觉得MFC比较难学,看书吧,看了就忘了,网上的一些教程又是写的含糊不清,故而学习起来很吃力...... 故此,本专栏亲自研究,实践,由易到难,层层深入,将调试过程中所遭所遇进行详细讲解,注意事项进行一一列举,希望能够帮助到各位初学MFC的小伙伴,避免走弯路,费时费力。......

hnjzfwy的博客 445

MFC---MFC应用程序框架分析(MFC应用程序框架)

上一讲讲的是VS2010应用程序工程中文件的组成结构,可能大家对工程的运行原理还是很模糊,理不出头绪,毕竟跟C++编程入门系列中的例程差别太大。这一节就为大家分析下MFC应用程序框架的运行流程。

Frank---7的博客 1278

全面解析MFC源码:深入学习与应用

本文还有配套的精品资源,点击获取 简介:《深入浅出MFC源代码》是为程序员深入理解并掌握Microsoft Foundation Classes (MFC)编写的书籍。MFC是微软提供的C++类库,主要用于Windows应用开发,尤其在桌面领域应用广泛。本书通过详尽的源码分析,使读者能够理解MFC核心原理,提升开发效率和程序质量。MFC的架构包括框架类、文档/视图架构、控件...

weixin_30336531的博客 1031

MFC图形绘制项目实战与源码分析

MFC库,即Microsoft Foundation Classes,为开发者提供了一个封装Windows API的框架,极大地简化了Windows应用程序的开发过程。它允许开发者使用C++进行面向对象编程,同时提供了一套标准的GUI组件,如窗口、按钮、编辑框等,以及文档/视图架构,以便构建结构化的应用程序。OnDraw()是CView类中的一个虚函数,用于定义视图绘制的逻辑。每当视图需要被重绘或更新时,MFC框架会调用OnDraw()函数。

weixin_42327217的博客 1021

MFC源码解读(一)最原始一个MFC程序,手写不用向导

从这一篇开始,详细记录一下MFC的源码解读 四个文件,分别为: stdafx.h,stdafx.cpp,hello.h,hello.cpp 代码如下: //stdafx.h #include <afxwin.h> //stdafx.cpp #include "stdafx.h" //hello.h class CMyWinApp:public CW...

weixin_34245169的博客 697

MFC单文档画图程序实战教程

Microsoft Foundation Classes(MFC)是一个C++库,包含一系列的类模板,用来帮助开发Windows应用程序。它封装了Windows API,使得编程更为高效和易于管理。MFC广泛应用于Windows桌面应用的开发,并支持面向对象的设计方法。Windows绘图系统主要由GDI(图形设备接口)组成,为应用程序提供了丰富的图形和文本输出能力。GDI使得开发者可以使用统一的API在不同的输出设备上进行绘图,而无需关注设备的具体细节。

weixin_35899324的博客 1077

MFC串口通信上位机程序源码:稳定高效的通信利器

MFC串口通信上位机程序源码:稳定高效的通信利器 去发现同类优质开源项目:https://gitcode.com/ 在嵌入式开发与工业自动化领域,串口通信是一种常见的通信方式。本文将为您介绍一个开源项目——MFC串口通信上位机程序源码,它不仅可以帮助您轻松实现串口通信,而且经过严格调试,确保稳定高效运行。 项目介绍 MFC串口通信上位机程序源码是基于MFC(Microsoft Foundation...

gitblog_06777的博客 857

深入浅出MFC源码实战分析(简体中文第二版)

Microsoft Foundation Classes(MFC)是微软公司推出的一套面向对象的C++库,它封装了Windows API,并提供了一种更为简洁和高效的方式来创建图形用户界面(GUI)程序。MFC不仅简化了窗口创建、消息循环等复杂操作,还支持多文档界面(MDI)和单文档界面(SDI)应用程序的开发。在Windows平台下进行MFC开发时,CWinApp类扮演着至关重要的角色。CWinApp是所有MFC应用程序的基类,它负责应用程序的初始化、消息循环、以及终止程序时的清理工作。

weixin_42361478的博客 769

基于VC++与MFC的屏幕保护程序开发实战源码

每一个MFC程序都必须定义一个全局的CWinApp派生类实例,它是整个应用程序的“中枢神经”。该类负责初始化COM库、注册窗口类、处理命令行参数,并启动消息循环。示例代码如下:public:// 全局实例,自动构造其中theApp是唯一的应用程序对象,其构造发生在main()或WinMain()执行之前。MFC运行时库会在程序启动时查找此类实例并调用其方法。是最重要的虚函数之一,开发者通常在此完成以下任务:解析命令行参数(区分 /s, /p, /c)

weixin_42452924的博客 874

《精通MFC程序设计》随书源码介绍

《精通MFC程序设计》随书源码介绍 去发现同类优质开源项目:https://gitcode.com/ 《精通MFC程序设计》是深入学习和掌握MFC(Microsoft Foundation Classes)进行Windows界面程序设计的权威指南。为了帮助读者更好地理解和实践书中的内容,我们提供了这本书的随书源码。 源码简介 本源码包含了《精通MFC程序设计》一书中各个章节的示例程序和代码,覆盖了...

gitblog_06793的博客 867

掌握MFC核心技术与实战源码分析

MFC(Microsoft Foundation Classes)是微软公司为了简化Windows应用程序的开发而推出的一套C++类库。自1992年推出以来,MFC已成为Windows平台上最受欢迎和最常用的开发框架之一。它封装了Windows API(应用程序编程接口),将复杂的底层通信简化为对象操作,极大地提高了开发效率和可维护性。MFC提供了一系列的控件类,用于处理用户界面的各个方面。以下是一些最常用的控件类:CButton:用于创建按钮控件,可以是命令按钮、复选框、单选按钮等。

weixin_35756690的博客 836

MFC系列 - 第一个MFC入门程序

     MFC,多年开发和教学,这门课程,新课改决定将它砍掉,Qt也是我们的趋势,同时在我的Qt系列中详细讲解了Qt的系列教学。MFC虽然很古老,但是还是得佩服微软搞得这套框架,让一代又一代Windows程序员无不熟练在心,犹如武功秘籍葵花宝典、虽然在界面UI这块让人痛心疾首、以及一大堆的宏定义让人摸不着头脑,每次讲课,一些学员就说这是不是Java,不就是VB吗,但是他的开发速度、以及效率、还有...

码农 2008

windows 自带开wifi 源码(功能应有尽有)批处理

windows 自带开wifi热点的 源码 基于hostednetwork命令,还有很多逻辑功能,做到应有尽有 无广告 功能应有尽有 批处理 hostednetwork 超小内存

进程注入工具MFCInject

MFC框架,远线程注入 刚打开需要点击刷新进程按钮,右键想要注入的进程,选择注入 选择要注入的DLL即可注入,注入成功后该进程会标红 也可以遍历模块查看是否注入成功 若注入的DLL有弹出窗口,卸载前需要关闭窗口 文件比较大,因为是静态编译 源码请见:https://github.com/plokDay/InjectTool

mfc140.dll文件丢失我们该怎么去解决?教你最便捷的5种mfc140.dll方法

如果在使用计算机的过程中,系统突然提示“mfc140.dll文件丢失”,这实际上是一种常见的问题。对于频繁使用电脑的用户来说,可能会不时地遇到DLL文件缺失的情况。今天,我将为大家提供详细的说明,并指导如何修复mfc140.dll文件缺失的问题。

电脑修复君的博客 1463

tmux + Claude Code 远程开发指南:从 WSL 配置到断线无忧

远程开发中,SSH 连接中断常导致后台任务丢失,这是困扰开发者的经典难题。tmux 作为终端复用器,通过将进程挂在常驻会话中,使其脱离 SSH 连接独立运行,从根本上解决了断线导致的任务终止问题。Claude Code 等 AI 编程代理需要长时间运行并保持交互上下文,恰好依赖这种会话持久化能力。结合 Windows Subsystem for Linux 提供类 Unix 环境,开发者可在 Windows 上实现稳定的远程开发工作流。本文将完整介绍从 WSL 环境配置、tmux 会话管理,到与 Claud

weixin_30423065的博客 348

MFC框架程序解析

可以看到窗口的创建虽然都由MFC框架处理,但其实现原理依旧和Windows程序一样,即设计、注册、创建、显示刷新、进入消息循环这一步骤。 优点就是前面提到的简化程序员的开发工作,但可以明显感觉到MFC框架对Windows系统的依赖性,这就限制了其对跨平台的支持。

SNAKEpc12138的博客 1962

零成本矩阵玩法:1人运营5个账号的自动化工具链配置(2025全平台实战)

通过“AI内容生产+工具链分发+自动化变现”的组合拳,即使是新手也能实现1人运营5个账号的规模化收益。关键在于选对工具与设计标准化流程。未来,矩阵运营的竞争将聚焦于工具使用效率与数据洞察深度,快人一步者方能抢占先机!

TuFuir的博客 3790

VSCode+Typst零配置写作指南:5分钟搞定论文排版环境(含实时预览技巧)

本文介绍如何利用VSCode和Typst快速搭建零配置的论文排版环境,5分钟内实现高效写作与实时预览。Typst作为轻量级排版工具,结合LaTeX的精度与现代化语法,显著提升学术写作效率,特别适合需要频繁调整格式的研究人员。

weixin_30642561的博客 113
上一篇: Windows异常世界历险记(三)——VC6中结构化异常处理机制的反汇编分析(上)
下一篇: MFC源码实战分析(二)——消息响应与处理机制初探
LPWSTR
博客等级 码龄10年 73粉丝 47原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值