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

作者:zieckey   ( zieckey@yahoo.com.cn  )

All Rights Reserved!

 

我们先看一个例子:

打开VC6.0,
依次点击:文件(File)->新建(New)->工程(Project)->MFC AppWizard(exe)
之后在右边输入路径和工程名称,这里暂定为:Test
单击确定(OK)按钮进入下一页面,选择单文本(Single Document),然后点击完成。
好了,一个基于MFC的应用程序框架已经完成。
现在我们来编译看看:Ctrl+F5
看到了效果图没?看到了对不?

好了,下面我们一起来看看这个我们没有添加一行代码的MFC程序。
看到左边的资源管理框,选择“ClassView”标签,可以看到下面几个类:
CAboutDlg,CMainFrame,CTestApp,CTestDoc,CTestView和一个全局变量:theApp
我们就从这个全局变量说起。看看这个MFC程序的执行过程。

我们知道创建一个完整的窗口需要经过下面四个操作步骤:
1.设计一个窗口类;
2.注册窗口类;
3.创建窗口;
4.显示及更新窗口。


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,
这里就不难明白上面说的“if (cs.lpszClass == NULL) //先判断该类是否注册,否则就注册 ”。

在 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 结构体,
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 函数,
从而实现了消息的循环。

至此,我们大概明白了一个MFC程序的构造过程和运行机理,其实和一个基本的windows窗口应用程序是一样的。
 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值