MFC源程序设计-计算机安全MFC源程序设计MFC程序设计之来龙去脉(MFC框架程序WINMAIN函数分析),到后来就没有再管了,其实那只是冰山一角.具体MFC是怎么运行的,还是没有交待清楚。说明:1、本文作者在VS2003中跟踪代码,此代码为VS2003中拷贝,使用MFC7。2、不同框架的MFC程序由所不同,本文以单文档为例。3、本文读者需要有一定的SDK的基础,不需要太多,至少知道它的基本框架和来龙去脉即可!4、文章只想起到说明作用,所以代码会有一些删除。学MFC,竟然还不知道MFC的MAIN函数在什么地方?怎么运行的?实在不高明。看过候捷(JJHOU)老师的《深入浅出MFC》的,对它一定很熟悉。呵呵,本文是献给没有看过那本书,但是又很希望学习MFC程序设计的朋友的。(没有看过那本书的朋友还不赶快去买?)其实本文,主要是对《深入浅出MFC》第六章的一个总结和补充罢了!(本文有该书不同的地方,也有一些笔者自己的见解!)言归正传。假如你用AppWizard一步一步NEXT下来,然后在CLASSVIEW中去找寻WINMAIN函数,那么你只有失望。MFC最大的特点是什么?封装!MFC的确封装的太好了,以至于很多想学习MFC的人都望而却步。闲话少说,还是继续我们今天的话题,MAIN函数!实话告诉你吧,即使你搜索所有的MFC生成的文件,都无法发现WINMAIN的字眼,那么它就近在什么地方呢?我相信你已经想到,MAIN函数应该在主要的应用程序文件中。难道是“您定义的程序名.cpp”这个文件?不错就是它。再Crtl+F一下,看有没有我们要找的WINMAIN函数?看来你又要失望了,但是你注意有这样一句:///////////////////////////////////////////////////////////////////////////////TheoneandonlyCMyAppobject本人建立的工程名为My。是不是很特别,再注意一下那句注释“TheoneandonlyCMyAppobject”,每个应用程序有且只用一个CMyApp对象。我想你应该想到了,WinMain函数每个程序也只能有一个,那么这个全局对象跟WinMain函数肯定有莫大的关系?没错,相信你的直觉。特别注意:深晓C++细节的人一定知道,全局对象优先于MAIN函数执行的道理。如果你不知道也没关系,那么我在这里告诉你:“全局对象优先于MIAN函数执行,且构建于栈中,切记,切记!”现在,我们该深入WinMain运行机制了,确切的说,应该是MFC的机制!首先,看看MFC的库文件把,它能给我们带来许多惊喜。(vc6的相应的目录是\MicrosoftVisualStudio\VC98\MFC\SRC;VC7相应的目录是\MicrosoftVisualStudio.NET2003\Vc7\atlmfc\src\mfc)现在我们就从这个全局下手,开始今天的旅途。CMyApptheApp;此时,系统会执行CMyApp的父类(CWinApp)构造函数,再执行CMyApp的构造函数。(先有老爹,再有儿子!),此时就会调用CWinApp的构造函数。CWinApp的构造函数(在VC提供的MFC代码中以“文中的一个字或词组”的方式查询关键字,此时打开APPCORE.CPP,以下使用相同搜索方式,不再复述。)找到以下内容:CWinApp::CWinApp(LPCTSTRlpszAppName){if(lpszAppName!=NULL)m_pszAppName=_tcsdup(lpszAppName);elsem_pszAppName=NULL;//initializeCWinThreadstateAFX_MODULE_STATE*pModuleState=_AFX_CMDTARGET_GETSTATE();AFX_MODULE_THREAD_STATE*pThreadState=pModuleState-m_thread;ASSERT(AfxGetThread()==NULL);pThreadState-m_pCurrentWinThread=this;ASSERT(AfxGetThread()==this);m_hThread=::GetCurrentThread();m_nThreadID=::GetCurrentThreadId();//initializeCWinAppstateASSERT(afxCurrentWinApp==NULL);//onlyoneCWinAppobjectpleasepModuleState-m_pCurrentWinApp=this;ASSERT(AfxGetApp()==this);......}OK,就到这里就可以了,仔细看上面代码,它已经完成了应用程序线程额的启动,它给予了我们程序的生命。现在请注意:pThreadState-m_pCurrentWinThread=this;pModuleState-m_pCurrentWinApp=this;这两行代码其实都是做的一件事儿。这段代码的意思是,获得了CMyApp的全局对象的this指针。(此时你肯定要疑问,为什么是CMyApp的指针?this目前是在CWinApp中啊?对此我的答案是,可是你是由CMyApp的对象引发的CWinApp的构造啊!!)这个指针可非一般的人物,稍后我们的很多工作都要靠它完成。CWinApp之中的成员变量将因为theApp这个全局对象的诞生而获得配置和初始值。构造完父类,现在构造子类。可是我们看到,AppWizard给我们的子类里它什么也没做?是的,这一切都听从你的安排!CMyApp::CMyApp(){//TODO:addconstructioncodehere,//PlaceallsignificantinitializationinInitInstance}接下来就是今天的主角儿了,搜索关键字“WinMain”,出现很多文件。别急,因为现在我们应该先看看WinMain的声明。打开appmodul.cpp:_tWinMain(HINSTANCEhInstance,HINSTANCEhPrevInstance,LPTSTRlpCmdLine,intnCmdShow){//callshared/exportedWinMainreturnAfxWinMain(hInstance,hPrevInstance,lpCmdLine,nCmdShow);}这里_tWinMain是为了支持UNICODE而命名的一个宏,真正起作用的是AfxWinMain,注意看看它的参数,是不是和SDK的WinMain函数一样?现在再搜索下AfxWinMain,其实在winmain.cpp中:intAFXAPIAfxWinMain(HINSTANCEhInstance,HINSTANCEhPrevInstance,LPTSTRlpCmdLine,intnCmdShow){ASSERT(hPrevInstance==NULL);intnReturnCode=-1;CWinThread*pThread=AfxGetThread();CWinApp*pApp=AfxGetApp();//AFXinternalinitializationif(!AfxWinInit(hInstance,hPrevInstance,lpCmdLine,nCmdShow))gotoInitFailure;//Appglobalinitializations(rare)if(pApp!=NULL&&!pApp-InitApplication())gotoInitFailure;//Performspecificinitializationsif(!pThread-InitInstance()){if(pThread-m_pMainWnd!=NULL){TRACE(traceAppMsg,0,Warning:Destroyingnon-NULLm_pMainWnd\n);pThread-m_pMainWnd-DestroyWindow();}nReturnCode=pThread-ExitInstance();gotoInitFailure;}nReturnCode=pThread-Run();......}此段代码注意五个细节:CWinApp*pApp=AfxGetApp();意为获得对象指针,其实就是刚才那个THIS。不记得了?指向CMyApp的那个!还值得注意的是,Afx意是全局的,随时你都可以调用它。(AFX就是MFC开发小组的开发代号,意为ApplicationFramework传说X只是为了好看,没实在意思?!)if(!AfxWinInit(hInstance,hPrevInstance,lpCmdLine,nCmdShow))AfxWinInit完成了线程的初始化和窗框类的注册。具体参看appinit.cpp中的定义。if(pApp!=NULL&&!pApp-InitApplication())其实pApp和pThread是同一个指针,都是指向CMyApp的指针,这里因为CMyApp中没有定义InitApplication,实际上就调用的CWinApp::InitApplication(),完成了MFC的内容管理。if(!pThread-InitInstance())因为CMyApp中改写了它,所以调用CMyApp中的,其实它也是初始化工作。此时也完成了默认窗口类的定义。假如你熟悉SDK编程的话,一定不会忘记窗口类的设计、注册、创建、现实及更新的步骤,此时MFC以为你设计好了默认的窗口类。现在你不禁要疑问,InitApplication()和InitInstance()有何不同?答案是,假如你执行一个程序,于是两个函数都会被调用;当你在不关闭前一个程序的前提下,再执行一个程序,那么就只执行后一个函数。nReturnCode=pThread-Run();这个一步骤在《深入浅出MFC》中被成为程序的活水源头,在我看来它就是你开车踩油门的步骤。待会我们会具体阐述!在设计窗口类以后,就应该是注册,MFC自动调用(跳转到)AfxEndDeferRegisterClass(WINCORE.CPP中),为你注册了五个窗口类,分别是:AfxWnd,AfxCreateBar,AfxMDIFrame,AfxFrameOrView,AfxOleControl以上窗口类MFC将自动转化成独立无二的类名,供其调用。在窗口的注册以后,就应该是窗口的创建工作,此时会调用CFrameWnd::Create(),该代码位于WINFRM.Cpp中BOOLCFrameWnd::Create(LPCTSTRlpszClassName,LPCTSTRlpszWindowName,DWORDdwStyle,constRECT&rect,CWnd*pParentWnd,LPCTSTRlpszMenuName,DWORDdwExStyle,CCreateContext*pContext){HMENUhMenu=NULL;if(lpszMenuName!=NULL){//loadinamenuthatwillgetdestroyedwhenwindowgetsdestroyedHINSTANCEhInst=AfxFindResourceHandle(lpszMenuName,RT_MENU);if((hMenu=::LoadMenu(hInst,lpszMenuName))==NULL){TRACE(traceAppMsg,0,Warning:failedtoloadmenuforCFrameWnd.\n);PostNcDestroy();//perhapsdeletetheC++objectreturnFALSE;}}m_strTitle=lpszWi