当前位置:文档之家› MFC入门之运行方法

MFC入门之运行方法

MFC入门之运行方法
MFC入门之运行方法

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 CREA TESTRUCT 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 == NU LL) //先判断该类是否注册,否则就注册”。

在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为提供了CREA TESTRUCT 结构体,

CREATESTRUCT

The CREA TESTRUCT 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窗口应用程序是一样的

相关主题
相关文档 最新文档