在一个windows程序中,winmain函数作为程序的入口函数,一个窗口程序是:设计窗口(给窗口设置相应的属性)——>注册窗口——>创建窗口——>显示并且更新窗口——>消息循环;
但是当创建一个MFC程序时候,并没有看到winmain函数之类的东西,并且之前的程序框架与MFC也大有不同。现在,先来看看MFC中的程序框架以及程序运行机制吧。
由于MFC是对其SDK的封装,所以程序运行逻辑方式应该是一样的。
在MFC程序中,同样还是有winmain函数参与,但是这个WinMain函数是在程序编译连接时,由链接器将该函数链接到程序的。知道WinMain的存在后,那么WinMain又是怎么跟其他类组织在一起的呢?
(1)CxxxApp 中,有一个theApp对象的全局对象,该对象就表示了应用程序本身。对于全局对象theApp,它是在程序进入WinMain函数之前为其分配的空间,同时,定义其的时候会调用它的构造函数。在程序中看到CxxxApp是 CWinApp的子类,当调用CxxxApp的构造函数之前,会调用其父类的构造函数。程序的初始化在CWinApp构造函数完成。
(2)AfxWinMain函数:WinMain函数实际上是通过调用AfxWinMain函数来完成其功能的。AfxWinMain源代码在MFC源代码的WINMAIN.CPP文件中。AfxWinMain首先通过调用AfxGetThread函数获得一个CWinThread类型的指针,接着调用AfxGetApp函数获得一个CWinApp类型的指针。由于CWinApp继承自CWinThread,AfxGetThread函数实际上返回的是AfxGetApp函数的结果,因此上面所说的AfxGetThread函数获得一个CWinThread类型的指针,接着调用AfxGetApp函数获得一个CWinApp类型的指针所得到的两个指针实际上是一致的。都指向theApp全局对象。
(3)InitInstance函数:接下来pThread和pApp调用了三个函数(在AfxWinMain所在的文件WINMAIN.CPP中可以看到)。分别是pApp->InitApplication();
pThread->InitInstance(); pThread->Run();三个函数。这三个函数完成了程序所需要的几个步骤:设计窗口类,注册窗口类,显示窗口类,消息循环,以及窗口过程函数。(通过进一步的跟进每个函数可以发现这三个函数最终需要调用跟win32中程序完成这些功能的函数的影子!)
设计和注册窗口:MFC 已经为我们预定义了一些默认的标准窗口类,而注册窗口类是由AfxEndDeferRegisterClass函数完成。 (AfxEndDeferRegisterClass函数首先获得窗口类的信息,如果该窗口类已经注册,直接返回一个真值,否则,调用 RegisterClass函数注册该窗口类。其与win32SDK中所使用的函数是一样的啊!)
创建窗口: 窗口的创建是由CWnd类中的CreateEx函数实现的,在MFC中,CFrameWnd类的Create函数内部调用了上述的CreateEx函数, 而前者又是由CrameWnd中的LoadFrame函数调用!!!在CreateEx函数的实现过程中,调用了PreCreateWindow,而后者 是一个虚函数,故此调用是调用子类的PreCreateWindow函数,之所以这样是在窗口产生之前让程序员能够有机会修改窗口的外观。参数类型是一个 CREATESTRUCT结构体。
显示与更新窗口:CxxxApp类中有一个m_pMainWnd的成员变量,是一个CWnd类型的指针,保存了应用程序窗口的指针。通过它调用与SDK中一样的ShowWindow与UpdateWindow函数完成任务。
消息循环:前面已经提到过pThread->Run();这个函数就是实现了消息循环。在这个函数中的for循环中,执行了我们认识的TransLateMessage与DisPatchMessage两个函数;
窗口过程: 在AfxEndDeferRegisterClass函数的源程序中,其中有一行眼熟的代码:wndcls.lpfnwndProc = DefWindowProc;当然MFC程序并不是把所有的消息都交给DefWindowProc窗口过程来处理。MFC中使用的是消息映射机制!
一个MFC消息响应函数在程序中有三处相关的信息:函数原型,函数实现,用来关联消息和消息响应函数的宏。(分别分布在头文件及源文件中)
头文件中在两个AFX_MSG 注释宏之间是消息响应函数的原型的声明。源文件中有两处:
(1)AFX_MSG_MAP注释宏之间的消息映射宏,通过这个宏把消息与消息响应函数关联起来;
(2)源文件中消息响应函数的实现代码。
MFC 中的消息映射机制的实现方法:在每个能接收和处理消息的类中,定义一个消息和消息的处理函数静态对照表,即消息映射表。在消息映射表中,消息与对应的消息处理函数指针成对出现。某个类能处理的所有的消息及其对应的消息处理函数的地址都列在这个类所对应的静态表中。当有消息需要处理时,程序只要搜索该消息静态表,查看表中是否存在该消息,就可以知道该类是否能够处理此消息。如果能,则依照静态表找到对应的消息处理函数。否则,将消息传给其父类。