




已阅读5页,还剩19页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
MFC编程(写给MFC初级者的速成宝典)正文MFC编程1微软基础类库(MFC:Microsoft Foundation Class)是微软为Windows程序员提供的一个面向对象的Windows编程接口,它大大简化了Windows编程工作。使用MFC类库的好处是:首先,MFC提供了一个标准化的结构,这样开发人员不必从头设计创建和管理一个标准Windows应用程序所需的程序,而是“站在巨人肩膀上”,从一个比较高的起点编程,故节省了大量的时间;其次,它提供了大量的代码,指导用户编程时实现某些技术和功能。对用户来说,用MFC开发的最终应用程序具有标准的、熟悉的Windows界面,这样的应用程序易学易用;另外,新的应用程序还能立即支持所有标准Windows特性,而且是用普通的、明确定义的形式。事实上,也就是在Windows应用程序界面基础上定义了一种新的标准MFC标准。一、MFC类库概念和组成类库是一个可以在应用中使用的相互关联的C+类的集合。Microsoft提供了一个基础类库MFC,其中包含用来开发C+和C+ Windows应用程序的一组类。基础类库的核心是以C+形式封装了大部分的Windows API。类库表示窗口、对话框、设备上下文、公共GDI对象如画笔、调色板、控制框和其他标准的Windows部件。这些类提供了一个面向Windows中结构的简单的C+成员函数的接口。MFC可分为两个主要部分:(1)基础类(2)宏和全程函数。1、MFC基础类:MFC中的类按功能来分可划分为以下几类: 基类 应用程序框架类 应用程序类 命令相关类 文档/视类 线程类 可视对象类 窗口类 视类 对话框类 属性表 控制类 菜单类 设备描述表 绘画对象类 通用类 文件 诊断 异常 收集 模板收集 其他支持类 OLE2类 OLE基类 OLE可视编辑包装程序类 OLE可视编辑服务器程序类 OLE数据传输类 OLE对话框类 其他OLE类 数据库类2、宏和全局函数:若某个函数或变量不是某个类的一个成员,那么它是一个全程函数或变量。Microsoft基本宏和全程函数提供以下功能: 数据类型运行时刻对象类型服务诊断服务异常处理 CString格式化及信息框显示消息映射应用消息和管理对象连接和嵌入(OLE)服务 标准命令和Windows IDs3、约定:全程函数以“Afx”为前缀,所有全程变量都是以“afx”为前缀,宏不带任何特别前缀,但是全部大写。常见的全局函数和宏有:AfxGetApp,AfxGetMainWnd,AfxMessageBox,DEBUG_NEW等,我们会在后面的章节中用到并对它们进行介绍。从继承关系来看,又可将MFC中的类分成两大类:大多数的MFC类是从CObject继承下来;另外一些类则不是从CObject类继承下来,这些类包括:字符串类CString,日期时间类CTime,矩形类CRect,点CPoint等,它们提供程序辅助功能。由于MFC中大部分类是从CObject继承下来的,CObject类描述了几乎所有的MFC中其他类的一些公共特性,因此我们有必要理解CObject类。 我们首先查看一下CObject类的定义,CObject类定义如下清单2.1所示:清单2.1CObject类的定义/ class CObject is the root of all compliant(顺从的、适应的) objectsclass CObjectpublic:/ Object model (types, destruction, allocation)virtual CRuntimeClass* GetRuntimeClass() const;virtual CObject(); / virtual destructors are necessary/ Diagnostic(诊断的) allocations(配置)void* PASCAL operator new(size_t nSize);void* PASCAL operator new(size_t, void* p);void PASCAL operator delete(void* p);#if defined(_DEBUG) & !defined(_AFX_NO_DEBUG_CRT)/ for file name/line number tracking using DEBUG_NEWvoid* PASCAL operator new(size_t nSize, LPCSTR lpszFileName, int nLine);#endif/ Disable the copy constructor and assignment by default so you will get/ compiler errors instead of unexpected behaviour if you pass objects/ by value or assign tected:CObject();private:CObject(const CObject& objectSrc); / no implementation(执行)void operator=(const CObject& objectSrc); / no implementation/ Attributespublic:BOOL IsSerializable() const;BOOL IsKindOf(const CRuntimeClass* pClass) const;/ Overridablesvirtual void Serialize(CArchive& ar);/ Diagnostic Supportvirtual void AssertValid() const;virtual void Dump(CDumpContext& dc) const;/ Implementationpublic:static const AFX_DATA CRuntimeClass classCObject;#ifdef _AFXDLLstatic CRuntimeClass* PASCAL _GetBaseClass();#endif;CObject类为派生类提供了下述服务:1、对象诊断。MFC提供了许多诊断特性,它可以:输出对象内部信息:CDumpContext类与CObject的成员函数Dump配合,用于在调试程序时输出对象内部数据。对象有效性检查:重载基类的AssertValid成员函数,可以为派生类的对象提供有效性检查。运行时访问类的信息:MFC提供了一个非常有用的特性,它可以进行运行时的类型检查。如果从CObject派生出一个类,并使用了以下三个宏(IMPLEMENT_DYNAMIC,IMPLEMENT_DYNCREATE或IMPLEMENT_SERIAL)之一,就可以:运行时访问类名安全可靠的把通用的CObject指针转化为派生类的指针比如,我们定义一个主窗口类CMyFrame:public CFrameWnd.然后我们使用这个类:CMyFrame *pFrame=(CMyFrame*)AfxGetMainWnd();pFrame-DoSomeOperation();AfxGetMainWnd是一个全局函数,返回指向应用程序的主窗口的指针,类型为CWnd*,因此我们必须对它进行强制类型转换,但我们如何知道是否转换成功了呢?我们可以使用CObject的IsKindOf()成员函数检查pFrame的类型,用法如下:ASSERT(pFrame-IsKindOf(RUN_TIMECLASS(CMyFrame);将上一语句插入到pFrame-DoSomeOperation()之前,就可以在运行时作类型检查,当类型检查失败时,引发一个断言(ASSERT断言声称),中断程序执行。2、对象持续性。通过与非CObject派生的档案类CArchive相结合,提供将多个不同对象以二进制形式保存到磁盘文件(Serilization)中以及根据磁盘文件中的对象状态数据在内存中重建对象(Deserilization)的功能。然而,MFC不仅仅是一个类库,它还提供了一层建立在Windows API的C+封装上的附加应用程序框架。该框架提供了Windows程序需要的多数公共用户界面。所谓应用程序框架指的是为了生成一般的应用所必须的各种软组件的集成。应用框架是类库的一种超集。一般的类库只是一种可以用来嵌入任何程序中的、提供某些特定功能(如图象处理、串行通信)的孤立的类的集合,但应用框架却定义了应用程序的结构,它的类既相互独立,又相互依赖,形成一个统一的整体,可以用来构造大多数应用程序。中国用户熟悉的Borland C+的DOS下的Turbo Vision和Windows下OWL(Object Windows Language)都是应用框架的例子。下面我们举个具体的例子来说明MFC所提供的应用程序框架,程序如清单2.2。清单2.2应用程序框架示例#include/derived(起源) an application classclass CMinMFCApp:public CWinApppublic:BOOL InitInstance();/Derive the main window classclass CMainWindow:public CFrameWndpublic:CMainWindow();DECLARE_MESSAGE_MAP();BEGIN_MESSAGE_MAP(CMainWindow,CFrameWnd)END_MESSAGE_MAP()/*CMinMFCApp Member Functions*/BOOL CMinMFCApp:InitInstance()m_pMainWnd=new CMainWindow();m_pMainWnd-ShowWindow(m_nCmdShow); m_pMainWnd-UpdateWindow(); return TRUE;/*CMainWindow member functions*/CMainWindow:CMainWindow()/constructorCreate(NULL,Min MFC Application,WS_OVERLAPPEDWINDOW,rectDefault,NULL,NULL);/*an instance of type CMinMFCApp*/CMinMFCApp ThisApp;清单2.2程序段定义了一个最小的MFC应用程序所需的框架程序。其中声明了CMinMFCApp类,它是从应用程序类CWinApp中派生下来的;和窗口CMainWindow类,它是从框架窗口CFrameWnd类派生出来。我们还用CMinMFCApp定义了一个全局对象ThisApp。读者也许会问,为什么没有WinMain函数?因为MFC已经把它封装起来了。在程序运行时,MFC应用程序首先调用由框架提供的标准的WinMain函数。在WinMain函数中,首先初始化由CMinMFCApp定义的唯一的实例,然后调用CMinMFCApp继承CWinApp的Run成员函数,进入消息循环。退出时调用CWinApp的ExitInstance函数。由上面的说明可以看到,应用程序框架不仅提供了构建应用程序所需要的类(CWinApp,CFrameWnd等),还定义了程序的基本执行结构。所有的应用程序都在这个基本结构基础上完成不同的功能。MFC除了定义程序执行结构之外,还定义了三种基本的主窗口模型:单文档窗口,多文档窗口和对话框作为主窗口。Visual C+提供了两个重要的工具,用于支持应用程序框架,它们就是前面提到AppWizard和ClassWizard。AppWizard用于在应用程序框架基础上迅速生成用户的应用程序基本结构。ClassWizard用于维护这种应用程序结构。二、MFC的优点Microsoft MFC具有以下不同于其它类库的优势: 完全支持Windows所有的函数、控件、消息、GDI基本图形函数,菜单及对话框。类的设计以及同API函数的结合相当合理。 使用与传统的Windows API同样的命名规则,即匈牙利命名法。 进行消息处理时,不使用易产生错误的switch/case语句,所有消息映射到类的成员函数,这种直接消息到方法的映射对所有的消息都适用。它通过宏来实现消息到成员函数的映射,而且这些函数不必是虚拟的成员函数,这样不需要为消息映射函数生成一个很大的虚拟函数表(V表),节省内存。 通过发送有关对象信息到文件的能力提供更好的判定支持,也可确认成员变量。 支持异常错误的处理,减少了程序出错的机会 运行时确定数据对象的类型。这允许实例化时动态操作各域 有较少的代码和较快的速度。MFC库只增加了少于40k的目标代码,效率只比传统的C Windows程序低5%。 可以利用与MFC紧密结合的AppWizard和ClassWizard等工具快速开发出功能强大的应用程序。 另外,在使用MFC时还允许混合使用传统的函数调用。三、MFC对消息的管理Windows消息的管理包括消息发送和处理。为了支持消息发送机制,MFC提供了三个函数:SendMessage、PostMessage和SendDlgItemMessage。而消息处理则相对来说显得复杂一些。MFC采用了一种新的机制取代C语言编程时对Windows消息的Switch/Case分支,简化了Windows编程,使程序可读性、可维护性大大提高。1、MFC对消息的处理MFC采用一种消息映射机制来决定如何处理特定的消息。这种消息映射机制包括一组宏,用于标识消息处理函数、映射类成员函数和对应的消息等。其中,用afx_msg放在函数返回类型前面,用以标记它是一个消息处理成员函数。类若至少包含了一个消息处理函数,那么还需要加上一个DECLARE_MESSAGE_MAP()宏,该宏对程序执行部分所定义的消息映射进行初始化。清单2.3演示了消息处理函数的例子:清单2.3 消息处理函数例子class CMainFrame:CFrameWndpublic:CMainFrame();protected:/AFX_MSG(CMainFrame)afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);afx_msg void OnEditCopy();afx_msg void OnClose();/AFX_MSGDECLARE_MESSAGE_MAP();成员函数OnCreate,OnEditCopy,OnClose分别用来处理消息WM_CREATE、ID_EDIT_COPY和WM_CLOSE。其中,WM_CREATE和WM_CLOSE是系统预定义消息,包含在Windows.h中。而ID_EDIT_COPY是菜单Edit-Copy的标识,也就是用户选择Edit-Copy菜单项时产生的消息,一般在资源文件头文件中定义。在类的实现部分给出这三个成员函数的定义,以及特殊的消息映射宏。上面的例子的消息映射宏定义如下:BEGIN_MESSAGE_MAP(CMainFrame,CFrameWnd)ON_WM_CREATE()ON_COMMAND(ID_EDIT_COPY, OnEditCopy)ON_WM_CLOSE()END_MESSAGE_MAP()消息映射宏由BEGIN_MESSAGE_MAP()和END_MESSAGE_MAP()。其中,BEGIN_MESSAGE_MAP宏包含两个参数CMainFrame类和CFrameWnd,分别代表当前定义的类和它的父类。在BEGIN_MESSAGE_MAP()和END_MESSAGE_MAP()之间,包含了主窗口要处理的各个Windows消息的入口。在本例中,包含三个消息。其中ON_WM_CREATE被用来指定缺省的成员函数OnCreate与WM_CREATE相对应。在MFC中,包含了大量的预定义消息映射宏,用来指定各种成员函数与各种形如WM_XXXX消息相对应。如ON_WM_CLOSE宏指定了WM_CLOSE消息的处理成员函数为OnClose。这时侯,只需要写出要处理的消息就够了,不必再写出处理函数。消息映射宏ON_COMMAND则被用来将菜单项和用户自定义的命令同它们的处理成员函数联系起来。在上例中,用户选择Edit-Copy菜单项时,系统执行OnEditCopy()函数。ON_COMMAND宏的一般定义形式如下:ON_COMMAND(command,command_function)其中,command为菜单消息或用户自定义消息,command_function为消息处理函数。MFC允许用户自定义消息,常量WM_USER和第一个消息值相对应,用户必须为自己的消息定义相对于WM_USER的偏移值,偏移范围在00x3FFF之间,这对绝大多数程序来说都是够用的。用户可以利用#define语句直接定义自己的消息:#define WM_USER1 (WM_USER+0)#define WM_USER2 (WM_USER+1)#define WM_USER3 (WM_USER+2)下表列出了Windows95中Windows消息值的范围。 常 量值消息值范围意 义 WM_USER0x04000x0000-0x03FFWindows消息 0x0400-0x7FFF用户自定义的消息 0x8000-0xBFFFWindows保留值 0xC000-0xFFFF供应用使用的字符串消息为了说明如何使用用户自定义消息,我们看一个例子,见程序清单2.4:清单2.4 使用用户自定义消息#include#define CM_APPLE (WM_USER+0)#define CM_ORANGE (WM_USER+1)class CMainFrame:CFrameWndpublic:CMainFrame();protected:afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);afx_msg void OnClose();/handle user select appleafx_msg LRESULT CMApple(WPARAM wParam, LPARAM lParam);/handle user select orangeafx_msg LRESULT CMOrange(WPARAM wParam, LPARAM lParam);DECLARE_MESSAGE_MAP();/相应的消息映射如下:BEGIN_MESSAGE_MAP(CMainFrame,CFrameWnd)ON_WM_CREATE()ON_MESSAGE(CM_APPLE, CMApple)ON_MESSAGE(CM_ORANGE,CMOrange)ON_WM_CLOSE()END_MESSAGE_MAP()第一个ON_MESSAGE宏用于指定 CM_APPLE 命令消息的处理成员函数为CMApple,而第二个ON_MESSAGE宏用于指定CM_ORANGE命令消息的处理函数为CMOrange。2、消息的发送Windows应用程序允许应用程序向自己发送消息、向其他应用程序发送消息,甚至可以向Windows操作系统本身发送消息(比如要求关闭操作系统或重新启动操作系统)。Windows提供了三个API函数用于发送消息,这三个函数是:SendMessage、PostMessage和SendDlgItemMessage。SendMessage用于向窗口发送消息,该函数说明如下:LRESULT SendMessage(HWND hWnd, /消息要发往的窗口的句柄UINT Msg, /要发送的消息WPARAM wParam, /消息的第一个参数LPARAM lParam /消息的第二个参数);该函数调用目标窗口的窗口函数,直到目标窗口处理完该消息才返回。PostMessage函数同SendMessage类似,它把消息放在指定窗口创建的线程的消息队列中,然后不等消息处理完就返回,而不象SendMessage那样必须等到消息处理完毕才返回。目标窗口通过GetMessage或PeekMessage从消息队列中取出并处理。PostMessage函数说明如下:BOOL PostMessage(HWND hWnd, /消息发往的窗口UINT Msg, /要发送的消息WPARAM wParam, /消息的第一个参数LPARAM lParam /消息的第二个参数);SendDlgItemMessage函数用于向对话框的某个控制发送消息,函数声明如下:LONG SendDlgItemMessage(HWND hDlg, /对话框句柄int nIDDlgItem, /对话框控件的IDUINT Msg, /要发送的消息WPARAM wParam, /消息的第一个参数LPARAM lParam /消息的第二个参数); MFC将这三个函数封装为CWnd类的成员函数,隐藏了窗口句柄和对话框句柄。这三个成员函数用于向本窗口发送消息,函数的说明如下:LRESULT SendMessage( UINT message, WPARAM wParam = 0, LPARAM lParam = 0 );BOOL PostMessage( UINT message, WPARAM wParam = 0, LPARAM lParam = 0 );LRESULT SendDlgItemMessage( int nID, UINT message, WPARAM wParam=0, LPARAM lParam=0);四、学习MFC的方法首先要对Windows API有一定的了解,否则无法深入学习MFC。至少要知道Windows对程序员来说意味着什么,它能完成什么工作,它的一些常用数据结构等。另一点是不要过分依赖于Wizards。Wizards能做许多工作,但同时掩饰了太多的细节。应当看看AppWizard和ClassWizard为你所做的工作。在mainfrm.cpp中运行调试器来观察一下MFC运行的流程。除非你理解了生成的代码的含义,否则无法了解程序是如何运行。还有很重要的一点就是要学会抽象的把握问题,不求甚解。许多人一开始学习Visual C+就试图了解整个MFC类库,实际上那几乎是不可能的。一般的学习方法是,先大体上对MFC有个了解,知道它的概念、组成、基本约定等。从最简单的类入手,由浅入深,循序渐进、日积月累的学习。一开始使用MFC提供的类时,只需要知道它的一些常用的方法、外部接口,不必要去了解它的细节和内部实现,把它当做一个模块或者说黑盒子来用,这就是一种抽象的学习方法。在学到一定程度时,再可以深入研究,采用继承的方法对原有的类的行为进行修改和扩充,派生出自己所需的类。学习MFC,最重要的一点是理解和使用MFC类库,而不是记忆。AppWizard所创建的文件根据可选项,AppWizard所创建的文件会略有不同。标准的AppWizard文件包括:工作区文件、项目文件和make文件应用程序源文件和头文件资源文件预编译头文件按可选项增加的AppWizard文件一、工作区、项目文件和make文件Hello.dsw:这是MFC自动生成的工作区文件,它包含当前工作区所包含的项目的信息。Hello.dsp:这是MFC生成的项目文件,它包含当前项目的设置、所包含的文件等信息。Hello.MAK:这是MFC项目的项目文件,这也是与NMAKE兼容的文件。如果选择了External make文件可选项,则可人工对它编辑,但不能利用Visual C+许多项目编辑特性。Hello.CLW:这个文件含有被ClassWizard用来编辑现有类或增加新类的信息。ClassWizard还用这个文件来保存创建和编辑消息映射和对话框数据所需的信息,或是创建虚拟成员函数所需的信息。二、应用程序源文件和头文件根据应用程序的类型单文档、多文档或基于对话框的,AppWizard将创建下述应用程序源文件和头文件中的某些文件。在本例中,AppWizard生成了如下文件:Hello.h:这是应用程序的主头文件,它含有所有全局符号和用于包含其它头文件的#include伪指令。Hello.CPP:这个文件是应用程序的主源文件。它将创建CHelloApp类的一个对象(从CWinApp派生),并覆盖InitInstance成员函数。MainFrm.cpp,MainFrm.h:这两个文件将从CFrameWnd(SDI应用程序)或CMDIFrameWnd(MDI应用程序)派生CMainFrame类。如果在AppWizard的Application Options页(6步中的第4步)中选择了对应的可选项的话,CMainFrame类将处理工具条按钮和状态条的创建。MAINFRM.CPP文件还含有MFC应用程序提供的默认工具条按钮的对象ID叫做buttons数组。HelloDoc.cpp,HelloDoc.h这些文件从CDocument类派生并实现名为CHelloDoc的文档类,并含有用于初始化文档、串行化(保存和装入)文档和用于调试诊断的一些成员函数的框架。HelloView.cpp,HelloView.h这些文件派生并实现名为CHelloView的视类,用于显示和打印文档数据。CHelloView类是从CView或它的派生类派生出来的,含有绘制视和用于调试诊断的一些成员函数框架。三、资源文件:AppWizard会创建一些与资源相关的文件。Hello.RC,RESOURCE.H,Hello.rc2这是项目的头文件及其资源文件。资源文件含有一般MFC应用程序的默认菜单定义和加速键表、字符串表。它还指定了缺省的About对话框和一个图标文件(RESHello.ICO)。资源文件了标准的MFC类的资源。如果指定了支持工具条,它还将指定工具条位图文件(RESTOOLBAR.BMP)。Hello.rc2用于存放Visual Studio不可直接编辑的资源。四、预编译头文件:STDAFX.CPP,STDAFX.H这两个文件用于建立一个预编译的头文件Hello.PCH和一个预定义的类型文件STDAFX.OBJ。由于MFC体系结构非常大,包含许多头文件,如果每次都编译的话比较费时。因此,我们把常用的MFC头文件都放在stdafx.h中,如afxwin.h、afxext.h、afxdisp.h、afxcmn.h等,然后让stdafx.cpp包含这个stdafx.h文件。这样,由于编译器可以识别哪些文件已经编译过,所以stdafx.cpp就只编译一次,并生成所谓的预编译头文件(因为它存放的是头文件编译后的信息,故名)。如果读者以后在编程时不想让有些MFC头文件每次都被编译,也可以将它加入到stdafx.h中。采用预编译头文件可以加速编译过程。应用程序执行机制一、WinMain函数在DOS下,程序的执行是从main函数开始的。在Windows下,对应的函数是WinMain。但是,如果浏览Hello程序的所有的方法和全局函数,是找不到WinMain函数的。MFC考虑到典型的Windows程序需要的大部分初始化工作都是标准化的,因此把WinMain函数隐藏在应用程序的框架中,编译时会自动将该函数链接到可执行文件中。程序员可以重写WinMain函数,但一般不需要这么做。下面的程序清单3-1给出了WinMain函数的代码。其中,_tWinMain函数在DevStudioVcMfcsrcAppModul.cpp中定义,它所调用的AfxWinMain函数在同一目录下的WinMain.cpp中定义。名字是_tWinMain函数而不是WinMain,是考虑到对不同字符集的支持,在tchar.h中有_tWinMain的宏定义。在ANSI字符集下编译时,_tWinMain就变成WinMain,在Unicode下编译时,_tWinMain就变成wWinMain。提示:Unicode是具有固定宽度、统一的文本和字符的编码标准。由于Unicode采用的是16位编码,因此可以包含世界各地的书写系统的字符和技术符号(如中文也在Unicode之中),从而克服了ASCII码在表示多语言文本上的不足之处,扩大了ASCII码7位编码方案的好处。Unicode同等地对待所有的字符,并且在表示各种语言的任何字符时既不需要换码序列(escape)也不需要控制代码。Win32和Visual C+很好的支持Unicode字符集。清单3-1 _tWinMain函数定义/ export WinMain to force(强制) linkage(联接) to this moduleextern int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPTSTR lpCmdLine, int nCmdShow);#ifdef _MACextern C int PASCAL#elseextern C int WINAPI#endif_tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPTSTR lpCmdLine, int nCmdShow)/ call shared/exported WinMainreturn AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);AfxWinMain函数定义:/ Standard WinMain implementation(执行)/ Can be replaced as long as AfxWinInit is called firstint AFXAPI AfxWinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,LPTSTR lpCmdLine, int nCmdShow)ASSERT(hPrevInstance = NULL); int nReturnCode = -1;CWinApp* pApp = AfxGetApp();/ AFX internal initializationif (!AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow)goto InitFailure; / App global initializations (rare)ASSERT_VALID(pApp);if (!pApp-InitApplication()goto InitFailure;ASSERT_VALID(pApp); / Perform specific initializationsif (!pApp-InitInstance()if (pApp-m_pMainWnd != NULL)TRACE0(Warning: Destroying non-NULL m_pMainWndn);pApp-m_pMainWnd-DestroyWindow();nReturnCode = pApp-ExitInstance();goto InitFailure;ASSERT_VALID(pApp); nReturnCode = pApp-Run();ASSERT_VALID(pApp);InitFailure:#ifdef _DEBUG/ Check for missing AfxLockTempMap callsif (AfxGetModuleThreadState()-m_nTempMapLock != 0)TRACE1(Warning: Temp map lock count non-zero (%ld).n,AfxGetModuleThreadState()-m_nTempMapLock);AfxLockTempMaps();AfxUnlockTempMaps(-1);#endifAfxWinTerm();return nReturnCode;应用程序执行时,Windows自动调用应用程序框架内部的WinMain函数。如清单3-1所示,WinMain函数会查找该应用程序的一个全局构造对象,这个对象是由CWinApp派生类构造的,有且只有一个。它是一个全局对象,因此在程序启动时,它就已经被构造好了。随后,WinMain将调用这个对象的InitApplication和InitInstance成员函数,完成应用程序实例的初始化工作。随后,WinMain调用Run成员函数,运行应用程序的消息循环。在程序结束时,WinMain调用AfxWinTerm函数,做一些清理工作。二、应用程序类每个应用程序必须从CWinApp派生出自己的应用程序类,并定义一个全局的对象。该应用程序类包含了Windows下应用程序的初始化、运行和结束过程。基于框架建立的应用程序必须有一个(且只能有一个)从CWinApp派生的类的对象。在Hello程序中,我们从CWinApp中派生出一个CHelloApp类,并定义了一个全局对象theApp。CHelloApp类在hello.cpp中定义。要访问应用程序类构造的对象,可以调用全局函数AfxGetApp()。AfxGetApp()返回一个指向全局对象的指针。可以通过对它进行强制类型转换,转换为我们派生的应用程序类。比如:CHelloApp* pApp=(CHelloApp*)AfxGetApp();在CHelloApp应用程序类中,我们还重载了CWinApp的成员函数InitInstance。InitInstance函数主要完成以下工作:设置注册数据库,载入标准设置(最近打开文件列表等)、注册文档模板。其中注册文档模板过程中隐含地创建了主窗口。接着,处理命令行参数,显示窗口,然后返回、进入消息循环。下面的程序清单3.2给出了Hello程序的InitInstance函数代码。清单3.2 InitInstance函数BOOL CHelloApp:InitInstance()AfxEnableControlContainer();/ Standard initialization/ If you are not using these features and wish to reduce the size/ of your final executable, you should remove from the following/ the specific initialization routines you do not need.#ifdef _AFXDLLEnable3dControls(); / Call this when using MFC in a shared DLL#elseEnable3dControlsStatic(); / Call this when linking to MFC statically#endif/ Change the registry key under which our settings are stored./ You should modify this string to be something appropriate/ such as the name of your company or organization.SetRegistryKey(_T(Local AppWizard-Generated Applications); LoadStdProfileSettings(); / Load standard INI file options (including MRU)/ Register the applications document templates. Document templates/ serve as the connection between documents, frame windows and views.CSingleDocTemplate* pDocTemplate;pDocTemplate = new CSingleDocTemplate(IDR_MAINFRAME,RUNTIME_CLASS(CHelloDoc),RUNTIME_CLASS(CMainFrame), / main SDI frame windowRUNTIME_CLASS(CHelloView);AddDocTemplate(pDocTemplate);/ Parse command line for standard shell commands, DDE, file openCCommandLineInfo cmdInfo;ParseCommandLine(cmdInfo);/ Dispatch commands specified on the command lineif (!ProcessShellCommand(cmdInfo)return FALSE;/ The one and only window has been initialized, so show and update it.m_pMainWnd-ShowWindow(SW_SHOW);m_pMainWnd-UpdateWindow();return TRUE;在CWinApp的派生类中,必须重载InitInstance函数,因为CWinApp并不知道应用程序需要什么样的窗口,它可以多文档窗口、单文档窗口,也可以是基于对话框的。Run成员函数WinMain在初始化应用程序实例后,就调用Run函数来处理消息循环。Run成员函数不断执行消息循环,检查消息队列中有没有消息。如果有消息,Run将其派遣,交由框架去处理,然后返回继续消息循环。如果没有消息,Run将调用OnIdle来做用户或框架可能需要在空闲时才做的工作,象后面我们讲到的用户接口更新消息处理等。如果既没有消息要处理,也没有空闲时的处理工作要做,则应用程序将一直等待,直到有事件发生。当应用程序结束时,Run将调用ExitInstance。消息循环的流程图如图3-10所示。图3-10 Run成员函数的消息循环关闭应用程序用户可以通过选择File-Exit菜单或点主窗口的关闭按钮,关闭主框架窗口,来终止应用程序。此时,应用程序类首先删除m_pMainWnd主框架窗口对象,然后退出Run函数,进而退出WinMain,在退出WinMain后删除TheApp对象。几种窗口类型一、框架窗口框架窗口为应用程序的用户界面提供结构框架,它是应用程序的主窗口,负责管理其包容的窗口,一个应用程序的最顶层的框架窗口是应用程序启动时创建的第一个窗口。MFC提供三种类型的框架窗口:单文档窗口,多文档窗口(MDI),对话框。MFC单文档窗口一
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 材料采购低价合同范本
- 农村鱼池招标合同范本
- 国产木屋租赁合同范本
- 水果买卖运输合同范本
- 影楼员工协议合同范本
- 回肠癌护理查房
- 呼肠孤病毒重症感染护理查房
- 成套设备合同范本
- 销售提成违约合同范本
- 国际工程专业合同范本
- 肝胆外科专科知识题库及答案
- 滁州市珠龙广卫绢云母粉厂滁州市南谯区将军山绢云母矿1万吨-年露天采矿工程项目环境影响报告书
- 人民医院心血管外科临床技术操作规范2023版
- 2023年江苏小高考历史试卷
- 主要组织相容性复合体及其编码分子
- 优化物理教学策略的思考(黄恕伯)
- 中国移动-安全-L1,2,3(珍藏版)
- 2017年全国大学生数学建模A题
- 2023年专升本计算机题库含答案专升本计算机真题
- scratch3.0编程校本课程
- GB/T 1685-2008硫化橡胶或热塑性橡胶在常温和高温下压缩应力松弛的测定
评论
0/150
提交评论