转自: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 函数,从而实现了消息的循环。