MFC之程序启动机制

一 程序启动机制

1.theApp对象,CWinApp子类对象,CWinApp继承自CWinThread.每个MFC程序有且仅有一个theApp对象,该对象代表当前程序本身

2.启动流程:

  a) 全局对象theApp构造。首先进入CWinApp构造函数。其中有下面两句代码:

    i. pThreadState->m_pCurrentWinThread=this;

    ii. pModuleState->m_pCurrentWinApp=this;由于此处是父类构造函数。根据多态原理可知,此处this是子类对象地址。子类对象theApp作为当前的线程对象和app对象,即iii和iv所说

    iii. theApp对象地址保存到模块状态信息中

    iv. theApp对象地址保存到当前线程信息中

  b) _tWinMain函数->AfxWinMain函数

    i. 首先:进入下面两句代码:CWinThread* pThread=AfxGetThread()和CWinApp* pApp=AfxGetApp().其中进入AfxGetThread函数中.主要代码如下:

    CWinThread* pThread=pState->m_pCurrentWinThread;

    if(pThread==NULL)

      pThread=AfxGetApp();

    return pThread;

  其中此处pState和CWinApp构造函数中是同一个,AfxGetApp函数赋值给pThread。此处的pThread就是this.故可得出:这两句代码,通过AfxGetApp/AfxGetThread获取theApp对象地址。

    ii. AfxGetApp函数内部调用afxGetCurrrentWinApp宏,该宏定义:

    #define afxGetCurrentWinApp AfxGetModuleState()->m_pCurrentWinApp.因此可看出AfxGetThread和AfxGetApp返回的都是theApp对象地址

    iii. theApp->InitApplicaion:初始化程序

    iv. theApp->InitInstance:重要代码逻辑如下:

      1. 文档模版类对象把文档对、视窗、框架窗口组合到一起,并添加到模板框架,代码:

      pDocTemplate=new CSingleDocTemplate(IDR_MAINFRAME,RUNTIME_CLASS(CTestDoc),RUNTIME_CLASS(CMainFrame),RUNTIME_CLASS(CTestView));组合

      AddDocTemplate(pDocTemplate);

      2. 显示窗口、更新窗口.代码

      m_pMainWnd->ShowWindow(SW_SHOW);

      m_pMainWnd->UpdateWindow();

    v. 设计和注册窗口类在AfxEndDeferRegisterClass函数中进行.在文档视图框架中,CMainFrame窗口创建前会调用PreCWreateWindow,该函数中首先会调用父类CFrameWnd类的PreCreateWindow函数,父类函数首先调用AfxDeferRegisterClass函数宏,该宏展开就是AfxEndDeferRegisterClass函数注册窗口类

    vi. 创建窗口:LoadFrame()->CMainFrame::Create->CFrameWnd::Create()->CWnd::CreateEx扩展函数(非虚函数)窗口窗口.注意CreateEx函数中创建窗口前会掉用PreCreateWindow(虚函数)函数。据上所述,此时窗口类已经被注册。那么此时调用该函数是可以让程序员在此处修改窗口参数。因为PreCreateWindow虚函数,参数为引用类型且参数和CreateEx一致。因      此,在子类中重写PreCreateWindow函数,会影响到父类CWnd,就会创建一个符合我们预期的窗口

    vii. .pThread->Run:消息循环

      1. 是一个for死循环,PumpMessage是核心,PumpMessage返回0退出死循环。进入PumpMessage中可知,当取得WM_QUIT消息时,PumpMessage返回false,run函数内部return ExitInstance().run函数通过PeekMessage函数获取消息

      2. 进入PumpMessage函数:

       BOOL CWinThread::PumpMessage()

       {

         if(!::GetMessage(&m_msgCur,NULL,NULL,NULL,NULL))

         {

          ...

          return FALSE;

        }

        ...

        if(m_msgCur.message!=WM_KICKIDLE && !PreTranslateMessage(&m_msgCur))

        {

          ::TranslateMessage(&m_msgCur);

          ::DispatchMessage(&m_msgCur);

        }

        return TRUE;

      }

      //需要注意:消息在翻译转发之前,会调用PreTranslateMessage,因此该函数内会进行一些消息筛选,若有些消息接收不到,可重写该函数

     3. 有消息时,通过PumpMessage(消息泵,会在其中调用GetMessagw,TranslateMessage,DispatchMessage函数)提取、翻译、派发消息,直至收到WM_QUIT消息返回错误,程序退出

     4. 无消息时,theApp->OnIdle做空闲处理

     5. Run 获取并调度 Windows 消息,直到应用程序收到 WM_QUIT 消息。 如果应用程序的消息队列当前不包含任何消息,则会 Run 调用 OnIdle 来执行空闲时处理。 传入消息将进入 PreTranslateMessage 成员函数进行特殊处理,然后进入 windows 函数 TranslateMessage 进行标准键盘转换; 最后, DispatchMessage 调用 windows 函数。

    viii:消息处理函数:在AfxEndDeferRegisterClass函数中,在窗口类参数中已传入默认消息处理函数。wndcls.lpfnWndProc=DefWindowProc.不过在MFC程序中并不是把所有消息交给DefWindowProc进行处理。更多的还是使用消息映射机制进行处理.

 

 

posted @ 2021-12-18 13:45  夜雨翛然  阅读(228)  评论(0)    收藏  举报