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,结束程序。

  • 相关阅读:
    document.getElementById("mytxt").style.left=""style.left在IE的FF中注意
    asp.net 用户控件中 使用相对路径的解决方法 图片路径问题(用户控件、图片路径) ,ResolveUrl
    探索 Block (一) (手把手讲解Block 底层实现原理)
    iOS 多线程开发 (概念与API简介)
    iOS 性能小点
    iOS runtime (二)(runtime学习之AutoCoding源码分析)
    探索 NSRunLoop (二)(NSRunLoop 自己动手实现SimpleRunLoop)
    iOS NSNotificationCenter (自己实现一个通知中心XMCNotificationCenter)
    iOS runtime (三)(runtime学习之YYModel源码分析)
    iOS runtime(一)(runtime 分析理解)
  • 原文地址:https://www.cnblogs.com/mthoutai/p/7043538.html
Copyright © 2011-2022 走看看