MFC程序的启动过程与相关函数执行顺序
- 格式:doc
- 大小:45.50 KB
- 文档页数:8
MFC的程序执行顺序很多刚学MFC的人都会被MFC给弄的晕头转向。
以前传统的C语言中的main()不见了,window sdk api 中的WinMain()函数也不见了,到底用MFC编写的程序是如何开始运行的呢?到底MFC有没有遵从最基本的C++的标准呢?到底MFC的代码运行的顺序又是怎么样的呢?那么多个文件,那么多函数,到底哪一个先运行,哪一个后运行,哪一个调用哪一个,哪一个又被哪一个调用(你看晕了吧?那么多“哪一个”^_^)?这里这么复杂,到底最真是的是怎么一回事呢?我开始学习的时候,也是一头雾水,什么都不明白,但是为了能先学习一些其他的,我囫囵吞枣的看了过去,先学习了CDIALOG和CVIEW的一些用法,并能编出了一个很简单的程序。
前几天,上网的时候,看到好多人都在看《孙鑫vc++讲座》视频教程,好像大家反应还不错,于是,我就去找个地方下载下来看了。
刚好今天看到了MFC的运行机制,里面讲到了MFC的运行顺序。
孙同学在视频中是利用实例,利用断点,然后不断的进行调试运行,以实事(实事胜于雄辩啊!!!)告诉我们,MFC是如何开始运行的。
下面,我就根据我看到的教程,和网上一些前辈整理出来的材料在整理:重点:MFC运行机制执行顺序各个函数用途以及调用顺序孙同学在视频中反复说明的是:MFC的程序和C语言的程序,从执行原理上说,是完全一致的。
抓住这一点,那么对于理解MFC程序的运行机制也就相对于简单了。
C中的main函数就相当于MFC中的WinMain函数。
感兴趣的可以利用VC的断点设置自己跟踪下面讲述的各个函数,就明白它的执行顺序了。
一、C语言程序执行步骤在C语言中,大约的步骤如下:1,全局变量内存分配例子如下:#include <iostream.h>int a=88;main(){cout<<a<<endl;}如果我们在main前设置断点,我们就会发现,在进入main之前,a就已经存在了。
很是空闲最近.转载一些东西吧..就当是复习...再不看看,就忘光了MFC 应用程序的操作步骤可归结为四步:(1) 创建应用程序对象theApp(2) 执行MFC提供的WinMain()函数(3) WinMain()调用InitInstance()函数,此函数创建文档模板,主框架窗口,文档和视图(4) WinMain()调用Run()函数,此函数执行主消息循环,以获取和分派Windows消息。
WinMain()是函数的入口点,该函数的主要任务是完成一些初始化的工作和维护了一个消息循环。
他们的工作流程如下:入口(WinMain())---->MyRegisterClass()---->InitInstance ()--->while消息循环。
函数由入口开始执行,之后调用 MyRegisterClass()注册窗口类,之后InitInstance ()生成并显示窗口,这样之后,就完成了一个窗口的初始化工作了(当然,在MyRegisterClass(),InitInstance ()中都需要调用相应的API函数来具体的实现),然后就是维护消息循环,至此,程序的基本结构就差不多建立了。
以后程序的运作就靠个消息循环来推动了.1、创建Application object对象theApp程序一开始生产一个(且只有一个)Application object对象theApp,也即一个CWinApp对象,这个全局对象一产生,便执行其构造函数,因为并没有定义CMyWinApp构造函数,所以即执行CWinApp类的构造函数。
该函数定义于APPCORE.CPP第75行,你可以自己搜出来啃一啃,因此,CWinApp之中的成员变量将因为theApp这个全局对象的诞生而获得配置与初值。
2、WinMain登场用SDK编程序时,程序的入口点是WinMain函数,而在MFC程序里我们并没有看到WinMain函数,哦!~ 原来她是被隐藏在MFC代码里面了。
MFC流程MFC程序文件名为Test.所以产生的5个类分别为1、CAboutDlg继承于CDialog2、CMainFrame继承于CFrameWnd1、CTestApp继承于CWinApp1、CTestDoc继承于CDocument1、CTestView继承于CView一、窗口产生流程1、设计窗口类2、注册窗口类3、产生窗口4、显示窗口5、更新窗口二、MFC中的细节1、WinMain函数的地址在C:\Program Files\Microsoft Visual Studio\VC98\MFC\SRC\APPMODUL.CPP文件中extern "C" int WINAPI_tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPTSTR lpCmdLine, int nCmdShow){// call shared/exported WinMainreturn AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);}其中_tWinMain是WinMain的宏定义如下: (此定义在文件C:\Program Files\Microsoft VisualStudio\VC98\Include\TCHAR.H中)#define _tWinMain WinMain而_tWinMain调用的是AfxWinMain.2、theApp全局对象先于WinMain运行产生全局对象,在程序入口函数WinMain加载时,系统就已经为全局变量或全局对象分配了存储空间,并为它们赋了初始值。
存放在静态数据区。
每一个MFC程序有且仅有一个从应用程序类(CWinApp)派生的类。
每一个MFC程序实例有且仅有一个该派生类的实例化对象,也就是theApp全局对象。
该对象表示应用程序本身。
由于在子类的构造之前会先调用其父类的构造函数。
MFC程序流程程序的诞生application object产生,内存于是获得配置,初值设立afxWinMain执行afxwinInit,调用afxInitThread把消息队列加大afxWinMain执行 InitApplication 是CWinApp的虚函数,通常不该写afxWinMain执行 InitInstance 是CWinApp的虚函数,必须改写CMyFrameWnd构造式调用Create ,产生窗口,回到InitInstance中继续执行ShowWindow 显示窗口执行UpdateWindow 发送WM_PAINT回到AfxWinMain 执行Run,进入循环。
程序开始运作程序获得WM_PAINT消息。
(藉由CWinApp::Run中的::GetMessage循环)WM_PAINT经由DispatchMessage送到窗口函数CWnd::DefWindowProc中。
CWnd::DefWindowProc将消息绕行过消息映射表格(Message Map)绕行过程中发现有吻合项目,于是调用项目中对应的函数,此函数是应用程序利用BEGIN_MESSAGE_MAP和END_MESSAGE_MAP之间的宏设立起来的。
标准消息的处理历程亦有标准命名,例如WM_PAINT必然由OnPaint处理程序的死亡:使用者按关闭。
发送WM_CLOSECMyFrameWnd并没有设置WM_CLOSE处理例程,于是交给于设置之处理例程。
预设函数对于WM_CLOSE的处理方式是调用::DestroyWindow并因而发出WM_DESTROY预设之WM_DESTORY处理方式是调用::PostQuitMessge发出WM_QUITCWinApp::Run收到WM_QUIT后会结束内部消息循环,然后调用ExitInstance,CWinApp的虚函数如果CMyWinApp改写了ExitInstance,那么CWinApp::Run就调用CMyWinApp::ExitInstance.回到AfxWinMain 执行 AfxWinTerm,结束程序。
执行一个windows应用程序包括初始化,运行和终止三大任务,MFC中的应用类封装了windows应用程序要做的这三大任务,这三大任务对应的三个主要函数就是InitInstance(),Run()和ExitInstance()。
应用类的基类是CWinApp类,MFC AppWizard自动生成的应用程序框架中的应用类就是由CWinApp类派生的。
注:应用程序必须有而且只能有一个CWinApp派生类,而且这个类只能有一个对象,这个对象是一个全程对象,即theAppCWinApp类有下面几个关键的虚函数,可供用户重载:InitInstance(),Run(),ExitInstance(),OnIdle()其中InitInstance()函数是必须重载的,而通常情况下也只需要重载InitInstance(),其他函数用户根据需要决定是否重载。
由于InitInstance()必须重载,所以在MFC AppWizard自动生成的应用程序框架中就自动重载了应用程序运行过程:InitInstance() 注:因为AppWizard已经重载了InitInstance(),所以这里调用的InitInstance()就是程序中重载的InitInstance() Run()注:WinMain()函数隐藏在应用框架内部,是看不到的。
InitInstance()函数:顾名思义,InitInstance()函数就是初始化实例。
Windows对同一个应用程序可以运行多个实例。
比如,如果已经在运行任务管理器,用户还可以再一次或多次启动任务管理器。
这样,系统就有多个任务管理器同时在运行,这些运行着的任务管理器就是任务管理器应用程序的多个运行实例。
当每次启动某个应用程序的一个实例时,WinMain()函数都要调用InitInstance()函数。
Run()函数:应用程序的大部分时间都是在应用类的Run()成员函数中打转转。
WinMain()函数在调用InitInstance()函数进行初始化完毕之后,就调用Run()函数来处理消息循环。
MFC程序中消息以及函数的处理顺序简介MFC应用程序中处理消息的顺序1.AfxWndProc()该函数负责接收消息,找到消息所属的CWnd对象,然后调用AfxCallWndProc2.AfxCallWndProc() 该函数负责保存消息(保存的内容主要是消息标识符和消息参数)供应用程序以后使用,然后调用WindowProc()函数3.WindowProc()该函数负责发送消息到OnWndMsg()函数,如果未被处理,则调用DefWindowProc()函数4.OnWndMsg()该函数的功能首先按字节对消息进行排序,对于WM_COMMAND消息,调用OnCommand()消息响应函数,对于WM_NOTIFY消息调用OnNotify()消息响应函数。
任何被遗漏的消息将是一个窗口消息。
OnWndMsg()函数搜索类的消息映像,以找到一个能处理任何窗口消息的处理函数。
如果OnWndMsg()函数不能找到这样的处理函数的话,则把消息返回到WindowProc()函数,由它将消息发送给DefWindowProc()函数5.OnCommand()该函数查看这是不是一个控件通知(lParam参数不为NULL,如果lParam参数为空的话,说明该消息不是控件通知),如果它是,OnCommand()函数会试图将消息映射到制造通知的控件;如果他不是一个控件通知(或者如果控件拒绝映射的消息)OnCommand()就会调用OnCmdMsg()函数6.OnCmdMsg()根据接收消息的类,OnCmdMsg()函数将在一个称为命令传递(Command Routing)的过程中潜在的传递命令消息和控件通知。
例如:如果拥有该窗口的类是一个框架类,则命令和通知消息也被传递到视图和文档类,并为该类寻找一个消息处理函数MFC应用程序创建窗口的过程1.PreCreateWindow()该函数是一个重载函数,在窗口被创建前,可以在该重载函数中改变创建参数(可以设置窗口风格等等)2.PreSubclassWindow() 这也是一个重载函数,允许首先子分类一个窗口3.OnGetMinMaxInfo()该函数为消息响应函数,响应的是WM_GETMINMAXINFO消息,允许设置窗口的最大或者最小尺寸4.OnNcCreate()该函数也是一个消息响应函数,响应WM_NCCREATE消息,发送消息以告诉窗口的客户区即将被创建5.OnNcCalcSize()该函数也是消息响应函数,响应WM_NCCALCSIZE消息,作用是允许改变窗口客户区大小6.OnCreate()该函数也是一个消息响应函数,响应WM_CREATE消息,发送消息告诉一个窗口已经被创建7.OnSize()该函数也是一个消息响应函数,响应WM_SIZE消息,发送该消息以告诉该窗口大小已经发生变化8.OnMove()消息响应函数,响应WM_MOVE消息,发送此消息说明窗口在移动9.OnChildNotify()该函数为重载函数,作为部分消息映射被调用,告诉父窗口即将被告知一个窗口刚刚被创建MFC应用程序关闭窗口的顺序(非模态窗口)1.OnClose()消息响应函数,响应窗口的WM_CLOSE消息,当关闭按钮被单击的时候发送此消息2.OnDestroy()消息响应函数,响应窗口的WM_DESTROY消息,当一个窗口将被销毁时,发送此消息3.OnNcDestroy()消息响应函数,响应窗口的WM_NCDESTROY消息,当一个窗口被销毁后发送此消息4.PostNcDestroy() 重载函数,作为处理OnNcDestroy()函数的最后动作,被CWnd调用MFC应用程序中打开模式对话框的函数调用顺序1.DoModal()重载函数,重载DoModal()成员函数2.PreSubclassWindow()重载函数,允许首先子分类一个窗口3.OnCreate()消息响应函数,响应WM_CREATE消息,发送此消息以告诉一个窗口已经被创建4.OnSize()消息响应函数,响应WM_SIZE消息,发送此消息以告诉窗口大小发生变化5.OnMove()消息响应函数,响应WM_MOVE消息,发送此消息,以告诉窗口正在移动6.OnSetFont()消息响应函数,响应WM_SETFONT消息,发送此消息,以允许改变对话框中控件的字体7.OnInitDialog()消息响应函数,响应WM_INITDIALOG消息,发送此消息以允许初始化对话框中的控件,或者是创建新控件8.OnShowWindow()消息响应函数,响应WM_SHOWWINDOW消息,该函数被ShowWindow()函数调用9.OnCtlColor()消息响应函数,响应WM_CTLCOLOR消息,被父窗口发送已改变对话框或对话框上面控件的颜色10. OnChildNotify()重载函数,作为WM_CTLCOLOR消息的结果发送MFC应用程序中关闭模式对话框的顺序1.OnClose()消息响应函数,响应WM_CLOSE消息,当"关闭"按钮被单击的时候,该函数被调用2.OnKillFocus()消息响应函数,响应WM_KILLFOCUS消息,当一个窗口即将失去键盘输入焦点以前被发送3.OnDestroy()消息响应函数,响应WM_DESTROY消息,当一个窗口即将被销毁时,被发送4.OnNcDestroy()消息响应函数,响应WM_NCDESTROY消息,当一个窗口被销毁以后被发送5.PostNcDestroy() 重载函数,作为处理OnNcDestroy()函数的最后动作被CWnd调用打开无模式对话框的顺序1.PreSubclassWindow()重载函数,允许用户首先子分类一个窗口2.OnCreate()消息响应函数,响应WM_CREATE消息,发送此消息以告诉一个窗口已经被创建3.OnSize()消息响应函数,响应WM_SIZE消息,发送此消息以告诉窗口大小发生变化4.OnMove()消息响应函数,响应WM_MOVE消息,发送此消息以告诉窗口正在移动5.OnSetFont()消息响应函数,响应WM_SETFONT消息,发送此消息以允许改变对话框中控件的字体。
MFC启动和关闭线程1、启动线程:CWinThread* AfxBeginThread( 线程函数,this );2、通常导致线程终⽌的两种情况是:控制函数退出或不允许线程完成运⾏。
如果字处理器使⽤后台打印线程,若成功完成打印,则控制函数将正常终⽌。
但是,如果⽤户要取消打印,后台打印线程则不得不提前终⽌。
本主题介绍如何实现每⼀种情况,以及在终⽌后如何获取线程的退出代码。
(1)正常线程终⽌对于辅助线程,正常线程终⽌很简单:退出控制函数并返回表⽰终⽌原因的值。
可以使⽤函数或 return 语句。
⼀般情况下,0 表⽰成功完成,但这取决于您⾃⼰。
对于⽤户界⾯线程,该过程也很简单:从⽤户界⾯线程内调⽤ Platform SDK 中的。
PostQuitMessage 采⽤的唯⼀参数是线程的退出代码。
对于辅助线程,0 通常表⽰成功完成。
(2)过早的线程终⽌过早终⽌线程⼏乎⼀样简单:从线程内调⽤。
将所需的退出代码作为唯⼀参数传递。
这将停⽌执⾏线程、解除对线程堆栈的分配、分离附加到线程的所有 DLL 并从内存中删除线程对象。
必须从要终⽌的线程内调⽤ AfxEndThread。
如果要从其他线程终⽌线程,必须设置两个线程间的通信⽅法。
举⼀个例⼦:可以创建⼀个信号量,⽤WaitForSingleObject函数来检测该信号量的状态。
成员变量 m_hThreadEvent;m_hThreadEvent = CreateEvent( NULL, FALSE, FALSE, NULL );线程的执⾏函数:for( ; ;){DWORD dwRetVal;dwRetVal = WaitForSingleObject( m_hThreadEvent, 100 );if ( dwRetVal == WAIT_TIMEOUT ){// TODO:}else{// stop receive text thread.DWORD dwExitCode;GetExitCodeThread( m_pThreadRecv->m_hThread, &dwExitCode );AfxEndThread( dwExitCode, TRUE );}}要结束线程时,使⽤SetEvent,将信号量置为有信号。
mfc实现流程
MFC(Microsoft Foundation Class Library)是微软提供的一个类库,用于在Windows环境下开发基于C++的图形用户界面(GUI)应用程序。
使用MFC可以简化Windows应用程序的开发过程。
以下是使用MFC实现应用程序的基本流程:
1. 创建项目:在Visual Studio中创建一个新的MFC项目。
选择“File”菜单中的“New”->“Project”,然后选择“MFC Application”。
2. 设置项目属性:在项目创建后,需要设置一些属性,如应用程序类型(单文档或多文档)、使用的MFC版本等。
3. 设计界面:使用Visual Studio的设计器,在图形界面中添加需要的控件,如按钮、文本框等。
也可以手动编写代码来创建控件。
4. 编写代码:根据需要编写代码,包括处理用户输入、更新界面、访问数据库等。
MFC提供了许多类和函数,用于简化常见的编程任务。
5. 编译和运行:编译代码并运行应用程序,检查是否存在错误。
6. 调试:如果应用程序中存在错误,使用调试器来查找和修复问题。
7. 测试:进行彻底的测试,确保应用程序在不同情况下都能正常工作。
8. 部署:完成测试后,可以将应用程序部署到目标机器上。
以上是使用MFC实现应用程序的基本流程。
具体实现细节会根据具体需求和项目规模有所不同。
MFC程序的启动过程与相关函数执行顺序原文地址:/chuntian1919/blog/item/f5b7f5fd898e2c1408244d3c.html了解MFC程序的启动过程,对于初学者来讲,了学习MFC很有帮助;对于不常用VC 的人来说,过一段时间就会忘记。
还是来记下来,方便以后查阅。
1、创建Application object对象theApp程序一开始生产一个(且只有一个)Application object对象theApp,也即一个CWinApp 对象,这个全局对象一产生,便执行其构造函数,因为并没有定义CMyWinApp构造函数,所以即执行CWinApp类的构造函数。
该函数定义于APPCORE.CPP第75行,你可以自己搜出来啃一啃,因此,CWinApp之中的成员变量将因为theApp这个全局对象的诞生而获得配置与初值。
2、WinMain登场用SDK编程序时,程序的入口点是WinMain函数,而在MFC程序里我们并没有看到WinMain函数,哦!~ 原来她是被隐藏在MFC代码里面了。
当theApp配置完成后,WinMain 登场,慢!细看程序,并没连到WinMain函数的代码啊!这个我也不知道,MFC早已准备好并由链接器直接加到应用程序代码中了,原来她在APPMODUL.CPP里面,好,我们就认为当theApp配置完成后,程序就转到APPMODUL.CPP来了。
那执行什么呢?看看下面从APPMODUL.CPP摘出来的代码:extern "C" int WINAPI_tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow){// call shared/exported WinMainreturn AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);}_tWinMain函数的“_t”是为了支持Unicode而准备的一个宏。
_tWinMain函数返回值是AfxWinMain函数的返回值,AfxWinMain函数定义于WINMAIN.CPP第21行,稍加整理,去芜存菁,就可以看到这个“程序进入点”主要做些什么事:int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow){int nReturnCode = -1;CWinApp* pApp = AfxGetApp();AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow);pApp->InitApplication();pApp->InitInstance()nReturnCode = pApp->Run();AfxWinTerm();return nReturnCode;}AfxGetApp()函数是取得CMyWinApp对象指针,故上面函数第6至8行相当于调用:CMyWinApp::InitApplication();CMyWinApp::InitInstance()CMyWinApp::Run();因而导致调用:CWinApp::InitApplication(); //因为CMyWinApp 并没有改写InitApplicationCMyWinApp::InitInstance() //因为CMyWinApp 改写了InitInstanceCWinApp::Run(); //因为CMyWinApp 并没有改写Run用过SDK写程序的朋友,现在可能会发出会心的微笑。
3、AfxWinInit——AFX内部初始化操作AfxWinInit是继CWinApp构造函数之后的第一个操作,主要做的是AFX内部初始化操作,该函数定义于APPINIT.CPP第24行,这里就不掏出来了,你自己搜出来啃吧!4、执行CWinApp::InitApplicationAfxWinInit之后的操作是pApp->InitApplication,我们已知道pApp指向CMyWinApp 对象,当调用:pApp->InitApplication();相当于调用:CMyWinApp::InitApplication();但是你要知道,CMyWinApp继承自CWinApp,而InitApplication又是CWinApp的一个虚拟函数,我们并没有改写它(大部分情况下不需改写它),所以上述操作相当于调用:CWinApp::InitApplication();此函数定义于APPCORE.CPP第125行,你自己搜出来看吧!我就不搬出来了,里面的操作都是MFC为了内部管理而做的(其实我也看不懂,知道有这回事就好了)。
5、执行CWinApp::InitInstance继InitApplication函数之后,AfxWinMain调用pApp->InitInstance。
当程序调用:pApp->InitInstance();相当于调用:CMyWinApp::InitInstance();但是你要知道,CMyWinApp继承自CWinApp,而InitInstance又是CWinApp的一个虚拟函数。
由于我们改写了它,所以上述操作就是调用我们自己(CMyWinApp)的这个InitInstance函数。
6、CFrameWnd::Create产生主窗口(并先注册窗口类)现在已经来到CWinApp::InitInstance了,该函数先new一个CMyFrameWnd对象,从而产生主窗口。
在创建CMyFrameWnd对之前,要先执行构造函数CMyFrameWnd::CMyFrameWnd(),该函数用Create函数产生窗口:CMyFrameWnd::CMyFrameWnd(){Create(NULL, "Hello MFC", WS_OVERLAPPEDWINDOW, rectDefault, NULL, "MainMenu");}其中Create是CFrameWnd的成员函数,它将产生一个窗口,用过SDK编程序的朋友都知道,要创建主窗口时要先注册一个窗口类,规定窗口的属性等,但,这里使用哪一个窗口类呢?Create函数第一个参数(其它参数请参考MSDN或《深出浅出MFC》详解)指定窗口类设为NULL又是什么意思啊?意思是要以MFC内建的空中类产生一个标准的外框窗口,但,我们的程序一般都没有注册任何窗口类呀!噢,Create函数在产生窗口之前会引发窗口类的注册操作。
让我们先挖出Create函数都做了些什么操作,Create函数定义于WINFRM.CPP的第538行(在此我就不把代码Copy过来了,你自己打开出来看吧),函数在562行调用CreateEx 函数,由于CreateEx是CWnd的成员函数,而CFrameWnd是从CWnd继而来,故将调用CWnd::CreateEx。
此函数定义于WINCORE.CPP第665行,下面是部分代码:BOOL CWnd::CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName,LPCTSTR lpszWindowName, DWORD dwStyle,int x, int y, int nWidth, int nHeight,HWND hWndParent, HMENU nIDorHMenu, LPVOID lpParam) {// allow modification of several common create parametersCREATESTRUCT cs;cs.dwExStyle = dwExStyle;cs.lpszClass = lpszClassName;cs.lpszName = lpszWindowName;cs.style = dwStyle;cs.x = x;cs.y = y;cs.cx = nWidth;cs.cy = nHeight;cs.hwndParent = hWndParent;cs.hMenu = nIDorHMenu;cs.hInstance = AfxGetInstanceHandle();cs.lpCreateParams = lpParam;if(PreCreateWindow(cs)){PostNcDestroy();return FALSE;}AfxHookWindowCreate(this);HWND hWnd = ::CreateWindowEx(cs.dwExStyle, cs.lpszClass,cs.lpszName, cs.style, cs.x, cs.y, cs.cx, cs.cy,cs.hwndParent, cs.hMenu, cs.hInstance, cs.lpCreateParams);...}用过SDK编程序的朋友,看到上面代码应该有一点感觉了吧,函数中调用的PreCreateWindows是虚拟函数,在CWnd和CFrameWnd之中都有定义。
由于this指针所指对象的缘故,这里应该调用的是CFrameWnd::PreCreateWindow。
该函数定义于WINFRM.CPP第521行,以下是部分代码:BOOL CFrameWnd::PreCreateWindow(CREATESTRUCT& cs){if (cs.lpszClass == NULL){VERIFY(AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG));cs.lpszClass = _afxWndFrameOrView; // COLOR_WINDOW background }...}其中AfxDeferRegisterClass是一个定义于AFXIMPL.H中的宏。
该宏如下:#define AfxDeferRegisterClass(fClass) AfxEndDeferRegisterClass(fClass) 注:这里有宏和《深入浅出MFC》的不一样,以上代码是从Visual C++ 6.0摘取。
AfxEndDeferRegisterClass定义于WINCORE.CPP第3619行,该函数很复杂,主要是注册五个窗口类(哇!终于看到窗口类了,怎么用5个呢?我还不清楚),不同类的PreCreateWindow成员函数都是在窗口产生之前一刻被调用,准备用来注册窗口类。