注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

being23

写给未来的自己

 
 
 

日志

 
 
关于我

真正的坚定,就是找到力量去做自己喜欢的事情,并为之努力,这样才会觉得生活是幸福的。

网易考拉推荐

2011.06.28  

2011-06-28 19:59:38|  分类: Tech |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

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

我们先看一个例子:

打开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窗口应用程序是一样的.

Technorati 标签: MFC
  评论这张
 
阅读(278)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017