MFC程序的启动过程

MFC执行流程 MFC流程   |字号 订阅 MFC程序文件名为Test. 所以产生的5个类分别为 1、CAboutDlg继承于CDialog 2、CMainFrame继承于CFrameWnd 1、CTestApp继承于CWinApp 1、CTestDoc继承于CDocument 1、CTestView继承于CView 一、窗口产生流程 1、设计窗口类 阅读详情

MFC程序的启动过程

绪论

我们在Win32中知道一个Windows窗口程序需要在主函数中经过注册窗口、创建窗口、显示窗口、消息循环、窗口的消息处理函数进行消息处理五个部分进行实现的。但是在MFC生成的的函数中我们没有见到主函数,但我们却能够创建窗口、处理消息。那么,它是如何执行的呢。接下类让我们揭盖MFC的神秘面纱,了解MFC的启动过程。

要想了解win32的执行过程和消息机制请观看这篇文章windows窗口创建流程及window消息机制详解

第一个MFC的程序

为了能够更好的了解MFC的执行过程,我们将使用Win32创建项目,然后修改为MFC的项目。因为win32的项目和MFC的项目取决于能否使用MFC库

项目创建过程

  1. 创建win32项目,在项目属性–>高级,将MFC的使用改成使用MFC库

  2. 添加CPP文件,包含#include <afxwin.h>

  3. 书写代码
    (1)定义自己的框架类,派生自CFrameWnd类。
    (2) 定义自己的应用程序类,派生自CWinApp类,并定义构造函数以及重写InitInstance虚函数,在程序中创建并显示窗口。
    代码如下:

       CMyWinApp::CMyWinApp()
       {
           
       }
       BOOL CMyWinApp: : InitInstance ()
       {
           CMDIFrameWnd* pFrame = new CMDIFrameWnd(); //创建框架类
           pFrame->Create(NULL,_T("MFCBase"));        //创建窗口
           m_pMainWnd = pFrame;                       //将框架类对象保存到theApp的属性中
           pFrame->ShowWindow(SW_SHOW);               //显示窗口
           pFrame->UpdateWindow();
           return TRUE;
       }
    

    (3) 创建全局变量 CMyWinApp的对象

MFC程序的启动

入口函数

MFC的入口函数和win32窗口程序相同,都是从WinMain入口。但是MFC库已经实现了WinMain函数,所以在程序中不需要实现。

因此,在Win32中WinMain由程序员自己实现,那么流程是程序员安排的,但到了MFC中,由于MFC库实现了WinMain,也就意味着MFC负责安排程序的流程。

执行流程

通过程序断点调试并通过伪代码的方式,获取MFC的执行流程。

在MFC中存在三个全局变量分别为 AFX_MODULE_STATE pModuleState 当前程序模块状态信息 、AFX_MODULE_THREAD_STATE pModuleThread当前模块线程状态信息、 AFX_THREAD_STATE pThreadState 当前线程状态信息

1. 全局对象 theApp的构造过程。
   //theApp基类构造函数
      CWinApp::CWinApp()
      {
          /*  该行代码,获取全局变量的地址
              第一个全局变量: AFX_MODULE_STATE  pModuleState 当前程序模块状态信息
          */
          //_AFX_CMDTARGET_GETSTATE();是一个宏,指代着AfxGetModutate();
         AFX_MODULE_STATE* pModuleState = _AFX_CMDTARGET_GETSTATE(); 
        
          /*
           获取第二个全局变量   AFX_MODULE_THREAD_STATE* pThreadState 当前程序线程状态信息 
          */
          
         AFX_MODULE_THREAD_STATE* pThreadState = pModuleState->m_thread;
      
         ASSERT(AfxGetThread() == NULL);//判断当前线程中的m_pCurrentWinThread是否为NULL
         
          /*
            m_pCurrentWinThread为空
            将theApp的保存到全局变量pThreadState的成员变量m_pCurrentWinThread中
            此时moduleState、 pThreadState、theApp的存储关系
            pModuleState->m_thread(pThreadState)->m_pCurrentWinThread(theApp)
          */
         pThreadState->m_pCurrentWinTread = this;  //该this指代theApp;
         //AfxGetThread内部执行过程见下面
         ASSERT(AfxGetThread() == this);          //判断是否赋值成功
         
          //这两个是theApp的属性
          this -> m_hThread = ::GetCurrentThread();
          this -> m_nThreadID = ::GetCurrentThread();
          
          /*
           此时pModuleState、 pThreadState、theApp的存储关系
              pModuleState->m_pCurrentWinApp(theApp)
              pModuleState->m_thread(pThreadState)->m_pCurrentWinThread(theApp)
          */
          pModuleState -> m_pCurrentWinAPP = this;
          ASSERT(AfxGetAPP() == this);
          //AfxGetApp的内部执行过程见下面
      }  

AfxGetThread内部执行过程

 AfxGetThread()
 {
  //获取全局变量  AFX_MODULE_THREAD_STATE* pThreadState 当前程序线程状态信息 
   AFX_MODULE_THREAD_STATE* pState = AfxGetModutateThreadState();
   CWinThread* pThread = pState -> m_pCurrentWinThread; //这是theApp;
   return pThread;   //返回的是theApp的地址
}

AfxGetApp的内部执行过程

   //AfxGetApp的内部执行过程见下面
AfxGetAPP()
   {
     //afxCurrentWinApp是一个宏指代着AfxGetModutate()-> m_pCurrentWinApp; //返回theApp  
     return afxCurrentWinApp;  
   }

总结:当程序启动时,构造theApp对象,调用父类CWInApp的构造函数。

​ 主要功能是将theApp对象保存到两个MFC的全局变量中。

​ AFX_MODULE_STATE moduleState 当前程序模块状态信息

​ AFX_MODULE_THREAD_STATE* pThreadState 当前程序模块线程状态信息

​ 补充: 综上所知,全局变量AFX_MODULE_STATE pModuleState 和 AFX_MODULE_THREAD_STATE* pModuleThread存在一一对应的关系,即pModuleThread->m_moduleState = pModuleState 、 pModuleState->m_thread = pModuleThread

2. MFC程序执行流程

通过调用堆栈获取InitInstance()的调用过程,找到MFC的main函数,MFC的main函数是_tWinMain(),它调用了AfxWinMain

AfxWinMain的执行过程

int AFXAPI AfxWinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance, 
                      _In_ LPTSTR lpCmdLine, int nCmdShow)
 {
     //首先获取了theApp  pThread和pApp都是全局变量theApp
    CWinThread* pThread = AfxGetThread();
    CWinApp* pApp = AfxGetApp();
    
    /*
      由pApp->InitApplication()可知,InitApplication()是theApp的成员函数,且InitApplication()
      是虚函数,我们没有对InitApplication()进行重写,因此它会执行父类的InitApplication()进行初始化
    */
   if (pApp != NULL && !pApp->InitApplication()) goto InitFailure;
   
    /*
      接下来又对实例进行初始化,InitInstance()是theApp的成员函数,并且我们进行了重写,
      因此执行我们的代码,在InitInstance()中,我们创建了Frame的对象并通过Frame创建了窗口,
      并将窗口进行显示。最后我们还将Frame对象保存到theApp的成员属性m_pMainWnd中
    */
   if (!pThread->InitInstance())
   {
       。。。。。。
   }
    //进行消息循环 该Run函数用了CWinThread::Run()函数 ,Run函数的执行在下面
    nReturnCode = pThread->Run();
}

CWinThread::Run()内部执行过程

    int CWinThread::Run()
    {
       //获取MFC中的第三个全局变量 该变量中存放着消息
       AFX_THREAD_STATE*  pState = AfxGetThreadState();
       BOOL bIdle = TRUE;
       for(;;)//死循环
       {
         //当消息队列中没有消息时进入循环
         while(bIdle && !::PeekMessage(&(pState->msgCur),NULL,NULL,NULL,PM_NOREMOVE))
         {
             //OnIdle()用来进行空闲处理 它是theApp的成员虚函数,可以进行重写
            if(this->OnIdle(this -> lIdleCount++)) this->bIdle = FALSE;
         }
         
         do
         {
           //当PumpMessage()返回false时就可以退出死循环,就是当GetMessage获取到WM_QUIT时才会退出
           if(!PumpMessage()) return ExitInstance();  //程序结束之前进行一些处理
                // PumpMessage()内部直接调用了全局函数AfxInternalPumMessage();
                 // AfxInternalPumMessage();的内部执行见下面    
         }while(::PeekMessage(&(pState->msgCur),NULL,NULL,NULL,PM_NOREMOVE));//有消息时不断循环
      }
 } 

AfxInternalPumMessage();的内部执行

 BOOL  AfxInternalPumMessage()
   {
   // GetMessage获得WM_QUIT消息时才会进入
       if(!::GetMessage(&(pState->msgCur),NULL,NULL,NULL))
       {
         return FALSE;
       }
       if(pState->m_msgCur.message != WM_KICKIDLE && !AfxPreTranslateMessae(&(pState->m_msgCur)))
       {
           //消息翻译
         ::TranslateMessage(&(pState->m_msgCur));
           //消息分发
         ::DispatchMessage(&(pState->m_msgCur));
       }
      return true;
   } 

总结:进入入口函数WinMain

​ 首先获取应用程序类对象theApp,

​ 利用theApp调用InitApplication,初始化当前应用程序的数据

​ 利用theApp调用InitInstance初始化程序,在函数中我们创建窗口并显示

​ 利用theApp调用CWinApp的Run函数进行消息循环

​ 如果没用消息,利用theApp调用OnIdle虚函数进行空闲处理

​ 程序退出利用theApp地址调用ExitInstance虚函数实现退出前的善后处理工作

通过以上可以知道theApp控制着程序的流程

结语

通过以上分析theApp作为MFC的全局变量,它控制的程序执行的流程,通过调用Win32的API来实现窗口创建的流程,但是在本节我们只看到了消息循环的实现。其实注册窗口、创建窗口、显示窗口以及窗口的消息处理函数都在theApp的成员函数中InitInstance中的pFrame->Create(NULL,_T(“MFCBase”));实现,它的具体实现,请关注我的下一篇文章MFC的窗口创建机制。

【CAD二次开发】炸开所有的嵌套块 代码】【CAD二次开发】炸开所有的嵌套块。 阅读详情

相关推荐

VMware 17+Win10 22H2全栈配置指南|UEFI优化+GPU直通实战

​VMware下载:下载官网版本的Wmare 17 Pro (点击直达链接 )企业用户可选永久许可证,个人学习也可以直接安装使用,Win10镜像:微软官网下载22H2版ISO文件(附官方纯净版渠道 )

waicsdn_haha的博客 4021

MFC程序设计(三)程序启动机制

这就是MFC执行的流程所使用的虚函数。

2301_78838647的博客 750

SpringBoot不用三方框架,怎么动态调度定时任务,ScheduledExecutorService 详解

Spring Boot 提供了强大的定时任务支持,无需依赖任何第三方框架,即可轻松实现可配置的定时任务。通过使用 `@EnableScheduling` 注解启用定时任务支持后,我们可以利用 `@Scheduled` 注解来定义定时任务的方法,这些方法可以在指定的时间间隔或特定时间点自动执行。 我们还可以通过集成 `ScheduledExecutorService` 来实现灵活的定时任务管理。`ScheduledExecutorService` 是 Java 标准库的一部分,能够以固定速率或延迟执行任务,

横竖撇折点 1939

微软MFC程序运行的正确顺序

微软MFC程序运行的正确顺序

荔园微风的博客 1747

指标异常检测和诊断

贡献度,即用定量衡量的方式来说明:一个指标YYY的异动△Y△Y△Y,具体是由其中哪些成分XiX_iXi​带来了多少异动△Yi△Y_i△Yi​?

qq_43349542的博客 3167

解决windows10下无法安装.net framework 3.5(包括.net2.0和3.0)

入域电脑,win10系统中安装 .net framework 3.5(包括.net2.0和3.0)

God_me_1的博客 4万+

mfc启动过程

MFC windows

yang___xin的博客 722

Windows10 使用Apple Studio Display显示器的设置

AppleStudioDisplay显示器购买花了近1.5wRMB,由于为windows台式机,显卡为NVIDAGTX-1660,而AppleStudioDisplay只有雷电接口,尝试了很多种转接方式,均以失败告终,最终使用贝尔金VR线成功,,附图如下这边也测试过NVIDARTX-2060Super、NVIDAGTX-1650显卡,都是能点亮的,NVIDA1650存在关机重启后黑屏,不稳定现象,2060也存在关机重启后不亮现象,后面发现1660s很稳定。...

爱意随风起,人生不可弃。 1万+

MFC 程序执行流程

MFC 程序执行流程分析

qq_61553520的博客 2090

xctf攻防世界 MISC高手进阶区 low

1. 进入环境,下载附件 给出的一张bmp图片,没有其他信息 2. 问题分析 扔进binwalk中,没有发现有用信息 使用zsteg,没有有用信息 塞入StegSolve中,发现有点猫腻,如图: 有点二维码的感觉,emmm,需要像素处理,但不知道如何下手,参考网上的wp,发现是让使用lsb隐写,copy代码: from PIL import Image img = Image.open('./pic/low.bmp') img_tmp = img.copy() pix = img_tmp.load()

l8947943的博客 1万+

昇腾CANN实战:如何用DVPP+AIPP实现32路视频流毫秒级预处理(附性能对比)

本文深入探讨了昇腾CANN架构中DVPP和AIPP模块在32路视频流毫秒级预处理中的硬件加速技术。通过异构计算架构的优化,实现了从传统CPU方案的40.7毫秒到CANN方案3.4毫秒的显著性能提升,特别适用于智能安防领域的实时视频分析需求。文章详细解析了DVPP多通道并行设计和AIPP模型级预处理融合的技术细节,并提供了性能对比数据与实战调优经验。

alice7model的博客 919

MFC启动过程&单文档MFC程序的启动详细过程

MFC启动过程 1. 首先说一下MFC程序的启动过程. 每个MFC程序都有一个全局的应用程序类的对象, 在面向对象程度非常好的MFC程序中, 应该只有这一个全局的对象. MFC应用程序启动时, 首先创建这个应用程序对象, 比如对象名为theApp, 这时将调用这个对象的构造函数来初始化theApp.然后由应用程序框架调用MFC提供的AfxWinMain主函数. 在这个主函数中, 首先获

zyw_anquan的专栏 1万+

零基础入门simulink仿真--通信领域的调制解调技术:基于Simulink的PM信号调制与解调仿真建模示例

PM的基本原理是将基带信号(如语音或音乐信号)加载到高频载波信号的相位上。通过改变载波的瞬时相位,可以实现信息的传输。PM的优点包括抗噪声能力强、频谱利用率较高等,但其解调过程相对复杂。通过Simulink,我们可以通过模块化的建模方式实现PM信号的调制和解调过程,并观察信号在信道中的传输效果。通过本指南,我们介绍了如何基于Simulink搭建一个完整的PM信号调制与解调仿真模型,并进行仿真和性能评估。背景介绍:理解PM信号调制与解调的基本原理及其应用。所需工具和环境:列出进行PM仿真所需的工具和环境。

amy_mhd的博客 605

MFC窗口程序启动运行机制剖析

本文的测试环境: IDE:VS2010 + VC助手(GO按钮对后面的跟踪调试很有用) 操作系统:Win8.1

eldn__的专栏 4748

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

MFC程序的启动过程与相关函数执行顺序

了解MFC程序的启动过程,对于初学者来讲,了学习MFC很有帮助;对于不常用VC的人来说,过一段时间就会忘记。还是来记下来,方便以后查阅。 1、创建Application object对象theApp      程序一开始生产一个(且只有一个)Application object对象theApp,也即一个CWinApp对象,这个全局对象一产生,便执行其构造函数,因为并没有定义CMyWin

xunathan的专栏 814

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

MFC程序启动过程(VS 2005代码剖析)

启动前做的事:初始化全局变量。<br />大概做了以下四件事:appmodul.cpp 67行 通过调用函数AfxInitialize初始化了MFC的线程局部存储功能和程序全局信息,这些信息最重要的有以下两个:<br />afxstate.cpp 398行 PROCESS_LOCAL(_AFX_BASE_MODULE_STATE, _afxBaseModuleState)<br />afxstate.cpp 117行 THREAD_LOCAL(_AFX_THREAD_STATE, _afxThreadSta

huyinhou 2129

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

MFC程序的启动过程与相关函数的执行顺序

[转自:http://wenku.baidu.com/view/3bbcffdda58da0116c17499f.html] [JOEY:本篇实为《深入浅出MFC》第6章 MFC程序的生死因果的精简版,作者在原基础上作了删节、整理和说明,便于快速阅读。要是了解得更深入,最好还是阅读原著。] 1、创建Application object对象theApp     程序一开始产生一个(且只有一

skywalker_leo的专栏 1874

MFC程序启动过程

1.通知系统要执行某一程序(鼠标,键盘,命令行...)。 2.系统将程序家载入内存(shell),为程序分配资源(进程,主线程,内存)。在此过程中全局变量theApp内存被分配,在构造函数中调用基类CWinApp的构造函数,在此函数中将自身与系统分配的资源联系起来。 AFX_MODULE_STATE* pModuleState = AfxGetModuleState(); pModuleSta

pokeyode的专栏 724

MFC 程序启动过程及入口点

每个程序都是从WinMain进入的,只是进入的时候你不知道而已,单步的时候可以看到是从WinMain进入的 因为程序是从Main(WinMain)开始。但是在Main(WinMain)开始之前会对全局的变量或者对象进行初始化。故在MFC中,通过通过全局类(theApp)的初始化,进入theApp的构造函数,根据类的规则,初始子类的构造函数,必须先要运行父类的构造函数。在这过程...

醉逍遥的博客 4106
上一篇: windows窗口创建流程及window消息机制详解
下一篇: MFC的窗口创建机制
♚陌路,相逢☜
博客等级 码龄8年 21粉丝 13原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值