您好,欢迎访问三七文档
第2章MFC概述1MFC类库简介2剖析单文档程序流程3消息映射4命令路由信阳师范学院城市与环境科学系张兴国2.1MFC简介类库是一个可以在应用程序中使用的相互关联的类的集合。MFC库(Microsoft基本类库)是一个Windows应用程序框架,它把传统的Windows编程规范中的大多数内容封装成为各种类,它定义了应用程序的结构,并实现了标准的用户接口,提高了编程效率。Msdn中查看MFC类结构MFC分类CObject_derived类Non_CObject_derived类根类命令相关类应用程序类窗口类文档类视图类框架窗口类线程基类CObjectCCmdTargetCWinThreadCWinAppCWndCFrameWndCViewCDocument非CObject派生类通用工具类•CString•CTime•CRect•Cpoint•CSizeMFC支持类•CArchive•CDumpContext•CRuntimeClass•CFileStatus•CMemoryStateCTypePointerArray2.2剖析单文档程序流程(1)WinMain函数——入口在APPMODUL.cpp中,在vc开发环境中打开,在_tWinMain函数处设置断点,调试运行。该函数的参数和基于WindowsAPI中的WinMain函数一样,但是其名字不同。可以在_tWinMain函数处,gotodefination,发现是宏#define_tWinMainWinMain。(2)WinMain与其他类如何关联CTestAppCWinApp派生,表示应用程序类。在构造函数中设置断点。在源文件中找到CTestApptheApp,并设置断点。?先执行CTestApptheApp,然后WinMain?通过控制台应用程序模拟:#includeiostream.hclassCPoint{public:CPoint(){}};CPointpt;voidmain(){}ptmain()thaApp代表应用本身。在WindowsAPI程序中,是通过实例号来代表应用程序。CTestApp在构造时,首先会构造父类CWinApp,两者进行关联。CWinApp的构造函数AppCore.cpp中。其含有参数,子类构造是,需显示调用,而这里没有显示传递。如果其有缺省值,就不用了。查看其定义,gotodefination,发现有确实值。pThreadState-m_pCurrentWinThread=this;this代表theApp。theApp-WinMainWinMain函数中,调用AfxWinMain函数,其在WinMain.cpp文件中。CWinApp*pApp=AfxGetApp();//得到当前应用实例的指针在AfxWinMain函数中,完成应用程序设计、注册、创建、显示及更新、消息循环、窗口处理函数。pThread也指向当前应用,其调用InitInstance,因其是虚函数,所以实际调用的是CTestApp的InitInstance函数。theApp-WinMain-AfxWinMain(InitInstance)-CTestApp的InitInstance设计注册窗口:MFC提前预定义了几种窗口类,不用设计了。有AfxEndDeferRegisterClass(在WinCore.cpp中)注册。其中AfxRegisterClass函数中最终还是调用RegisterClass函数。创建窗口CMainFrame和CView从CWnd派生,都代表窗口,框架窗口在后。在CMainFrame中有PreCreateWindow,其中调用CFrameWnd::PreCreateWindow(cs)----在WINFRM.cpp中。其中,验证是否注册过该类型窗口。然后,赋类名。正常情况下,是在PreCreateWindow中进行注册。CreateWindow函数在WINCore.cpp中。CFrameWnd中LoadFrame函数-Create函数-CreateEx函数CreateEx中又调用了PreCreateWindow,好处在于在创建窗口之前有机会修改窗口样式。注:cs结构和CreateWindowsEx参数是一致的。显示及更新ProcessShell()创建窗口完成。m_pMainWnd为指向主框架的指针,ShowWindow(SW_SHOW)UpdateWindow();消息循环CWinThread::RunThreadCore.cpp中其中PumpMessage当WM_QUIT消息时退出PumpMessage函数实现中有GetMessage窗口过程函数是DefWindowProc,在vc中采用的是消息映射的方式,后续阐述。整个过程CTestApptheApp;CWinApp构造函数其中保存了指向theApp的指针CTestApp构造函数WinMain函数CTestAppInitInstancepThread-InitInstance在这个函数中进行了窗口类的设计、注册、创建、显示及更新。PumpMessage消息循环ThreadCore.cpp中CTestDoc其父类,CDocument文档代表数据,存储、加载等,视类完成数据显示、修改等。数据本身与数据的显示分离开来。几个类怎么结合起来的?CSingleDocTemplate组织起来。程序开始初始化全局对象theAppCWinApp类构造函数CHelloApp类构造函数AfxWinMain函数pApp-InitInstance()调用ProcessShellCommand()创建主框架窗口对象、视图对象、文档对象,创建主框架窗口和视图窗口并显示CWinThread::Run()WM_QUIT消息循环结束pApp-Run()CHelloApptheAppCWinApp*pApp=AfxGetApp();WinMainpApp-InitApplication();2.3消息映射在MFC中,消息映射机制的基本实现思想是:首先,将每个类所感兴趣的消息都关联到其对应的消息相应函数上生成消息映射表;然后,将基础类与其派生类的消息映射表连接起来,形成更大的消息映射网。这样,当有消息发生时,通过对比MFC窗口的消息映射表,应用程序便可知当前消息是否有可执行的消息处理函数。为了将一个类所感兴趣的消息及消息响应函数对应起来生成消息映射表。nMessage,nCode,nID,nLastID,nSig,pfn_MessageEntries[]pBaseMapplEntries通过在每个需要响应Windows消息的类中声明一个该结构体的变量messageMap,并让其BaseMap指针指向基类或者另一个类的messageMap变量,就可以形成消息映射网。•GetMessageMap():该函数获得当前类自身的消息映射表constAFX_MSGMAP*theClass::GetMessageMap()const\{return&theClass::messageMap;}\形成MFC对象的消息映射网之后,为了方便查找,还需要在想要响应Windows消息的类中加入以下两个函数:•_GetBaseMessageMap():该函数获取当前类的基类的消息映射表ConstAFX_MSGMAP*PASCALtheClass::_GetBaseMessageMap()\{return&baseClass::messageMap;}//inAfxwin.h#defineDECLARE_MESSAGE_MAP()\private:\staticconstAFX_MSGMAP_ENTRY_messageEntries[];\protected:\staticconstAFX_MSGMAPmessageMap;\staticconstAFX_MSGMAP*PASCALGetThisMessageMap();\virtualconstAFX_MSGMAP*GetMessageMap()const;\#defineBEGIN_MESSAGE_MAP(theClass,baseClass)\constAFX_MSGMAP*PASCALtheClass::_GetBaseMessageMap()\{return&baseClass::messageMap;}\constAFX_MSGMAP*theClass::GetMessageMap()const\{return&theClass::messageMap;}\AFX_COMDATAFX_DATADEFconstAFX_MSGMAPtheClass::messageMap=\{&theClass::_GetBaseMessageMap,&theClass::_messageEntries[0]};\AFX_COMDATconstAFX_MSGMAP_ENTRYtheClass::_messageEntries[]=\{\#defineEND_MESSAGE_MAP()\{0,0,0,0,AfxSig_end,(AFX_PMSG)0}\};\MFC消息映射网的连接MFC消息映射网的连接也是在初始化过程中完成的,其建立过程很简单。主要有关成员有:private:staticconstAFX_MSGMAP_ENTRY_messageEntries[];protected:staticconstAFX_MSGMAPmessageMap;和BEGIN_MESSAGE_MAP()宏开后的AFX_COMDATconstAFX_MSGMAPtheClass::messageMap={&baseClass::GetThisMessageMap,&theClass::_messageEntries[0]};该宏将pfnGetBaseMap赋值为其基类的messageMap地址;将AFX_MSGMAP_ENTRY*lpEntries赋值为该类的_messageEntries[0];这样一个类不仅拥有本类的messageMap,而且还拥有其基类的messageMap,依此类推MFC消息映射网的连接就建立了,最终的基类都是CCmdTarget命令路由有了MFC消息映射网就为命令传递打下了坚实的基础。Win32API程序员都熟悉传统的API编程都有一个WndProc回调函数来集中处理各种的Windows消息,然而在MFC中我们却怎么也看不见WndProc回调函数的踪影了。而MFC命令传递机制恰是为了将各种消息“拐弯抹角”地送到各个对应的WndProc函数的一种技术。MFC是如何将各种Windows消息准确的送到期该区的地方呢?MFC使用了钩子函数等技术来保证其准确性和全面性。不知大家是否还记得MFC在注册窗口类时作了什么?BOOLAFXAPIAfxEndDeferRegisterClass(LONGfToRegister{...////commoninitializationWNDCLASSwndcls;memset(&wndcls,0,sizeof(WNDCLASS));//startwithNULLdefaultswndcls.lpfnWndProc=DefWindowProc;...//}可以看到MFC注册时将wndcls.lpfnWndProc赋值为DefWindowProc函数,那么实际上是否消息都是由它处理的呢?显然不可能,Windows又不知道我们要处理什么消息。那么还有什么函数能帮我们处理消息呢?钩子实际上是一个处理消息的程序段,通过系统调用,把它挂入系统。每当特定的消息发出,在没有到达目的窗口前,钩子程序就先捕获该消息,亦即钩子函数先得到控制权。要实现Win32的系统钩子,必须调用SDK中的API函数SetWindowsHookEx来安装这个钩子函数,这个函数的原型是HHOOKSetWindowsHookEx(intidHook,HOOKPROClpfn,HINST
本文标题:vc2MFC概述.
链接地址:https://www.777doc.com/doc-2866022 .html