MFC程序的启动过程

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的窗口创建机制

  • 0
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值