MFC程序的构造过程和运行机理

来源:互联网 发布:js中闭包的作用 编辑:程序博客网 时间:2024/05/02 01:35

文件出处:http://tangfeng.javaeye.com/blog/93399

 

一个完整的窗口需要经过下面四个操作步骤:

1.设计一个窗口类
我们知道全局对象的构造函数会在main 函数之前执行,那么这个全局类对象:theApp在main函数执行前就已经分配好了内存空间,由其定义
class CTestApp : public CWinApp
{
    ....
}
可知,该全局类继承自CWinApp,那么可知在该对象创建的时候,CWinApp的构造函数会被调用。之后,系统进入main函数,在MFC程序中,main函数是 _tWinMain 函数,可以看看 _tWinMain 的定义会发现,其实 _tWinMain 就是 WinMain。
_tWinMain 函数在 Microsoft Visual Studio/VC98/MFC/SRC/APPMODUL.CPP
extern "C" int WINAPI
_tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
 LPTSTR lpCmdLine, int nCmdShow)
{
    // call shared/exported WinMain
    return AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
}
其实里面就一行代码,又调用了  AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow) 函数,
AfxWinMain 函数在 Microsoft Visual Studio/VC98/MFC/SRC/WINMAIN.CPP
在 AfxWinMain 函数里,先声明了一个 CWinThread 类对象 pThread
CWinThread* pThread = AfxGetThread();
然后调用 pThread->InitInstance() 函数,这个函数很重要,我们看看它的定义:在CWinThread类的头文件 AFXWIN.H 中,可以发现如下代码,
virtual BOOL InitInstance();
这说明 InitInstance() 函数是个虚函数,这里我们可以看看继承关系:
class CTestApp : public CWinApp
{
    ....
}
class CWinApp : public CWinThread
{
    ....
}
这样我们就可以明白CTestApp其实继承自CWinThread,好的,明白这一点后,我们再看看CWinApp的构造函数:
CWinApp::CWinApp(LPCTSTR lpszAppName)
{
    .....
    pThreadState->m_pCurrentWinThread = this;
    .....
}
这里我们看到了上面的一行代码,这里的这个this指针到底指向谁呢?根据虚拟函数的特性和继承性原理我们知道它指向的是CWinApp的派生类CTestApp的对象,至此我们明白在 AfxWinMain 函数里,
CWinThread* pThread = AfxGetThread();
CWinApp* pApp = AfxGetApp(); 
表明 pApp、pThread 实际指向的都是 CTestApp 类对象,那么在后面的 pThread->InitInstance() 函数实际调用的是 CTestApp 类的成员函数 InitInstance() 。
这样MFC就把用户新建的类和MFC提供的源代码联系起来了。

2.注册窗口类
我们的第一个MFC程序中的 CMainFrame 类有一个成员方法(函数)PreCreateWindow(CREATESTRUCT& cs)
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
    if( !CFrameWnd::PreCreateWindow(cs) )
        return FALSE;
    // TODO: Modify the Window class or styles here by modifying
    //  the CREATESTRUCT cs

    return TRUE;
}
它的实现里调用了 CFrameWnd::PreCreateWindow(cs)  ,
CFrameWnd::PreCreateWindow的具体实现文件是:Microsoft Visual Studio/VC98/MFC/SRC/WINFRM.CPP
打开看看,
BOOL CFrameWnd::PreCreateWindow(CREATESTRUCT& cs)
{
    if (cs.lpszClass == NULL)   //先判断该类是否注册,否则就注册
    {
        VERIFY(AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG));
        cs.lpszClass = _afxWndFrameOrView;  // COLOR_WINDOW background
    }

    if ((cs.style & FWS_ADDTOTITLE) && afxData.bWin4)
        cs.style |= FWS_PREFIXTITLE;

    if (afxData.bWin4)
        cs.dwExStyle |= WS_EX_CLIENTEDGE;

    return TRUE;
}
AfxDeferRegisterClass 在 Microsoft Visual Studio/VC98/MFC/SRC/AFXIMPL.H 中有定义,
#define AfxDeferRegisterClass(fClass) AfxEndDeferRegisterClass(fClass)
其实 AfxDeferRegisterClass 就是:AfxEndDeferRegisterClass,

在 Microsoft Visual Studio/VC98/MFC/SRC/WINCORE.CPP 文件中有 AfxEndDeferRegisterClass 函数的定义:
BOOL AFXAPI AfxEndDeferRegisterClass(LONG fToRegister)
{
   ...
}
可以看到他里面有很得if语句,这个函数就是注册窗口类。

3.创建窗口
我们的第一个MFC程序中的 CMainFrame 类有一个成员方法(函数)PreCreateWindow(CREATESTRUCT& cs),该方法中调用了 CFrameWnd::PreCreateWindow(cs) ,在 CFrameWnd 类的实现中,有一个 BOOL CFrameWnd::Create(...),在该函数中又调用了 CreateEx(...)
在这里完成了窗口的创建。MFC为提供了 CREATESTRUCT 结构体,The CREATESTRUCT structure defines the initialization parameters passed to the window procedure of an application
这是为了在子类中创建窗口之前有机会由用户修改窗口外观。

4.显示及更新窗口
BOOL CTestApp::InitInstance()函数,该函数实际就是窗口的创建和显示更新。

最后我们看看这个MFC程序的消息循环,在 Microsoft Visual Studio/VC98/MFC/SRC/THRDCORE.CPP 中:
int CWinThread::Run() 
函数体就是一个消息循环,run函数也是个虚函数,这里最终调用了 CWinThread 的派生类 CWinApp 的 派生类 CTestApp 的 run 函数,从而实现了消息的循环。

原创粉丝点击