zoukankan      html  css  js  c++  java
  • MFC的执行过程分析

    MFC程序的执行细节剖析

           MFC程序也是Windows程序,所以它应该也有一个WinMain。可是在程序中看不到它的踪影。事实上在程序进入点之前。另一个(并且仅有一个)全局对象(theApp)。这就是所谓的Application object,当操作系统将程序载入并激活时,这个全局对象获得配置,其构造函数会先运行。比WinMain更早。

    一 CWinApp代替WinMain

           CWinApp的派生对象被称为application object,能够想见,CWinApp本身就代表一个程序本体。所谓程序本体是与程序本身有关而不与窗体有关的数据或动作。CWinApp类定义例如以下:

    class CWinApp : public CWinThread

    {

        //startup args

        HINSTANCE m_hInstance;

        HINSTANCE m_hPrevInstance;

        LPTSTR m_lpCmdLine;

        int m_nCmdShow;

     

    //Runing args

    CWnd* m_pMainWnd;

    CWnd* m_pActiveWnd;

        LPCTSTR m_pszAppName;

        LPCTSTR m_pszRegistryKey;

       

    public:

        LPCTSTR m_pszExeName;       //executable name

        LPCTSTR m_pszHelpFilePath;  //default based on module path

        LPCTSTR m_pszProfileName;   //default based on app name

     

    public:

        virtual BOOL InitApplication();

     

        //overrides for implementation

        virtual BOOL InitInstance();

        virtual int ExitInstance();

        virtual int Run();

        virtual BOOL OnIdle(LONG lCount);

    };

           传统意义上SDK程序的WinMain所完毕的工作如今由CWinApp的三个函数完毕:

    virtual BOOL InitApplication();

           virtual BOOL InitInstance();

           virtual int Run();

    那么WndProc函数到哪里去了呢?CFrameWnd主要用来掌握一个窗体,你差点儿能够说它是用来代替SDK程序中的窗体函数的地位。

    MFC通过内建了一个所谓的Message Map机制,会把消息自己主动送到“与消息相应的特定函数”中去。

    有关Message Map实现机制请看另外一篇博客。

    二 程序执行过程分析

           如图所看到的,左半边MFC程序代码。右半部是我们自己写的程序代码。

           当程序開始运行时,theApp这个全局对象产生,于是构造函数运行起来。CWinApp的构造函数例如以下

    CWinApp::CWinApp(LPCSTR lpszAppName)

    {

        m_pszAppName = lpszAppName;

     

        //initialize CWinThread state

        AFX_MODULE_THREAD_STATE* pThreadState = AfxGetModuleThreadState();

        pThreadState->m_pCurrentWinThread = this;

        m_hThread = ::GetCurrentThread();

        m_nThreadID = ::GetCurrentThreadId();

     

        //initialize CWinApp state

        AFX_MODULE_STATE* pModuleState = AfxGetModuleState();

        pModuleState->m_pCurrentWinApp = this;

     

        //in non-running state until WinMain

        m_hInstance = NULL;

        m_pszHelpFilePath = NULL;

        ........

    }

           CWinApp之中的成员变量将由于theApp这个全局对象的诞生而获得配置与初值。theApp配置完毕后,WinMain登场。我们并未编写WinMain程序代码,这是MFC早就已经准备好并由链接器直接加到应用程序代码中:

    extern “c” int WINAPI

    _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)

    {

        return AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);

    }

    int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)

    {

        int nReturnCode = -1;

        CWinApp* pApp = AfxGetApp();

        AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow);

       

        pApp->InitApplication();

        pApp->InitInstance();

        nReturnCode = pApp->Run;

        AfxWinTerm();

        return nReturnCode;

    }

    当中。AfxGetApp是一个全局函数,定义域AFXWIN1.INL中:

    _AFXWIN_INLINE  CWinApp* AFXAPI AfxGetApp()

                { return afxCurrentWinApp; }

           #define afxCurrentWinApp  AfxGetModuleState()->m_pCurrentWinApp

           依据之前描写叙述的CWinApp::CWinApp()中的操作,能够知道AfxGetApp事实上就是取得CMyWinApp对象指针。所以,AfxWinMain中这种操作:

           CWinApp* pApp = AfxGetApp();

           pApp->InitApplication();

           pApp->InitInstance();

           nReturnCode = pApp->Run;

           事实上就相当于调用:

           CMyWinApp::InitApplication();

           CMyWinApp::InitInstance();

           CMyWinApp::Run();

          

           因而导致调用:

           CWinApp::InitApplication();

           CMyWinApp::InitInstance();//改写了父类的该方法,调用子类的

           CWinApp::Run();

    AfxWinInit——AFX内部初始化操作

           AfxWinInit是继CWinApp构造函数之后的第一个操作。下面是它的操作摘要

    BOOL AFXAPI AfxWinInit(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)

    {

        ASSERT(hPrevInstance == NULL);

        //set resource handles

        AFX_MODULE_STATE* pState = AfxGetModuleState();

        pState->m_hCurrentInstanceHandle = hInstance;

        pState->m_hCurrentResourceHandle = hInstance;

        //fill in the initial state for the application

        CWinApp* pApp = AfxGetApp();

        if(pApp != NULL)

        {

            //windows spcific initialization

            pApp->m_hInstance = hInstance;

            pApp->m_hPrevInstance = hPrevInstance;

            pApp->m_lpCmdLine = lpCmdLine;

            pApp->m_nCmdShow = nCmdShow;

            pApp->SetCurrentHandles();

        }

        //initialize thread specific data

        if(!afxContexIsDLL)

        {

            AfxInitThread();

        }

        return TURE;

    }

     

    CWinApp::InitApplication.

    BOOL CWinApp::InitApplication()

    {

        if(CDocManager::pStaticDocManager != NULL)

        {

            if(m_pDocManager == NULL)

            {

                m_pDocManager = CDocManager::pStaticDocManager;

            }

            CDocManager::pStaticDocManager = NULL;

        }

        if(m_pDocManager != NULL)

        {

            m_pDocManager->AddDocTemplate(NULL);

        }

        else

        {

            CDocManager::bStaticInit = FALSE;

        }

        return TRUE;

    }

    这些都是MFC为了内部管理而做的。

    CMyWinApp::InitInstance

           继InitApplication之后。调用InitInstance即调用CMyWinApp::InitInstance();

    也就是调用我们重写后的InitInstance函数。

    CFrameWnd::Create产生主窗体(并先注冊窗体类)

     

           CMyWinApp::InitInstance一開始new了一个CMyFrameWnd对象,准备用作主框窗体的c++对象。

    会调用CMyFrameWnd类的构造函数,从而调用Create函数它将产生一个窗体。在调用Create函数的过程中Create会调用CreateEx,CreateEx函数实现例如以下:

    BOOL CWnd::CreateEx(DWORD dwExstyle, LPCTSTR lpszClassName,

                        LPCTSTR lpszWindowName, DWORD dwStyle,

                        int x, int y, int nWidth, int nHeight,

                        HWND hWndParent, HMENU nIDorHMenu, LPVOID lpParam)

    {

        //allow modification of several         common create parameters

        CREATESTRUCT cs;

        cs.dwExstyle = dwExStyle;

        cs.lpszClass = lpszClassName;

        cs.lpszName = lpszWindowName;

        cs.style = dwStyle;

        cs.x = x;

        cs.y = y;

        cs.cx = nWidth;

        cs.cy = nHeight;

        cs.hwndParent = hWndParent;

        cs.hMenu = nIDorHMenu;

        cs.hInstance = AfxGetInstanceHandle();

        cs.lpCreateParams = lpParam;

     

        PreCreateWindow(cs);

        AfxHookWindowCreate(this);

        HWND hWnd = ::CreateWindow(.....);

        ........

     

    }

    到这里可能熟悉SDK编程的都会问那么窗体类呢,事实上窗体类在Create函数调用时窗体类參数传的NULL代表将以MFC内建的窗体类产生一个标准的外框窗体。

     

    窗体显示与更新

     

           CMyFrameWnd::CMyFrameWnd结束后。窗体已经诞生出来;程序流程又回到了CmyWinApp::InitInstance。于是调用ShowWindow函数令窗体显示出来,并调用UpdateWindow函数令hello程序发送出WM_PAINT消息。

           我们非常关心这个WM_PAINT消息是怎样送到窗体函数的手中。并且,窗体函数又在哪里?

           MFC程序是不是也像SDK程序一样。有一个GetMessage/DispatchMesage循环?

     

    CWinApp::Run

           程序执行到这,接下来将执行pApp->Run()即相当于调用CMyWinApp::Run();

    Run函数是CWinApp的一个虚函数,并且我们没有改写它。所以上述操作相当于调用CWinApp::Run();通过研读Run函数实现代码它会调用PumpMessage()函数。在这个函数中就是真正处理消息循环函数。

     

    三 整理

    1.程序的诞生:

    Application object 产生,内存于是获得配置,初值亦设立了。AfxWinMain

    运行AfxWinInit,后者有调用AfxInitThread,把消息队列尽量加大到96。

    AfxWinMain运行InitApplication。

    这是CWinApp的虚函数,我们通常不改写它。

    AfxWinMain运行InitInstance。

    这是CWinApp的虚函数,我们必须改写它。

    CMyWinApp::InitInstance new 了一个CMyFrameWnd对象。

           CMyFrameWnd构造函数调用Create,产生主窗体。

           回到InitInstance中继续运行ShowWindow。显示窗体。

           运行UpdateWindow。于是发出WM_PAINT。

           回到AfxWinMain。运行Run,进入消息循环。

    2.程序開始执行:

    程序获得WM_PAINT消息(藉由CWinApp::Run中的::GetMessage循环)。

    WM_PAINT经由::DispatchMessage送到窗体函数CWnd::DefWindowProc

    中。

           CWnd::DefWindowProc将消息传递过消息映射表格(Message Map)。

           传递过程中发现有相符项目,于是调用项目中相应的函数。此函数是应用程序利用BEGIN_MESSAGE_MAP和END_MESSAGE_MAP之间的宏设立起来的。

           标准消息的处理程序亦有标准命名。比如WM_PAINT必定由OnPaint处理。

    3.程序的死亡

    使用者单击【File/Close】,于是发出WM_CLOS。

    CMyFrameWnd并没有设置WM_CLOSE处理程序。于是交给默认的处理程序。

    默认的处理函数对于WM_CLOSE的处理方式是调用::DestroyWindow,并因

    而发出WM_DESTROY。

    CWinApp::Run收到WM_QUIT后会结束其内部消息循环。然后调用

    ExitInstance,这是CWinApp的一个虚拟函数。

           最后回到AfxWinMain,运行AfxWinTerm,结束程序。

  • 相关阅读:
    Python、PyCharm的安装及使用方法(Mac版)
    学习Java web技术
    Java Web基础教程
    JavaWeb--深入Servlet与JSP(运行原理)
    Servlet入门总结及第一个Servlet程序
    Mac系统安装和配置tomcat步骤详解
    Struts2进阶学习4
    Struts2进阶学习3
    Struts2基础学习2
    Struts2基础入门
  • 原文地址:https://www.cnblogs.com/mthoutai/p/7043538.html
Copyright © 2011-2022 走看看