MFC和Win32技术应用分析

MFC和Win32技术应用分析,第1张

  MFC Object和Windows Object的关系

  MFC中最重要的封装是对Win32 API的封装,因此,理解Windows Object和MFC++ Object (C++对象,一个C++类的实例)之间的关系是理解MFC的关键之一。所谓Windows Object(Windows对象)是Win32下用句柄表示的Windows *** 作系统对象;所谓MFC Object (MFC对象)是C++对象,是一个C++类的实例,这里(本书范围内)MFC Object是有特定含义的,指封装Windows Object的C++ Object,并非指任意的C++ Object。

  MFC Object 和Windows Object是不一样的,但两者紧密联系。以窗口对象为例:

  一个MFC窗口对象是一个C++ CWnd类(或派生类)的实例,是程序直接创建的。在程序执行中它随着窗口类构造函数的调用而生成,随着析构函数的调用而消失。而Windows窗口则是Windows系统的一个内部数据结构的实例,由一个“窗口句柄”标识,Windows系统创建它并给它分配系统资源。Windows窗口在MFC窗口对象创建之后,由CWnd类的Create成员函数创建,“窗口句柄”保存在窗口对象的m_hWnd成员变量中。Windows窗口可以被一个程序销毁,也可以被用户的动作销毁。MFC窗口对象和Windows窗口对象的关系如图2-1所示。其他的Windows Object和对应的MFC Object也有类似的关系。

  下面,对MFC Object和Windows Object作一个比较。有些论断对设备描述表(MFC类是CDC,句柄是HDC)可能不适用,但具体涉及到时会指出。

  从数据结构上比较

  MFC Object是相应C++类的实例,这些类是MFC或者程序员定义的;

  Windows Object是Windows系统的内部结构,通过一个句柄来引用;

  MFC给这些类定义了一个成员变量来保存MFC Object对应的Windows Object的句柄。对于设备描述表CDC类,将保存两个HDC句柄。

  从层次上讲比较

  MFC Object是高层的,Windows Object是低层的;

  MFC Object封装了Windows Object的大部分或全部功能,MFC Object的使用者不需要直接应用Windows Object的HANDLE(句柄)使用Win32 API,代替它的是引用相应的MFC Object的成员函数。

  从创建上比较

  MFC Object通过构造函数由程序直接创建;Windows Object由相应的SDK函数创建。

  MFC中,使用这些MFC Object,一般分两步:

  首先,创建一个MFC Object,或者在STACK中创建,或者在HEAP中创建,这时,MFC Object的句柄实例变量为空,或者说不是一个有效的句柄。

  然后,调用MFC Object的成员函数创建相应的Windows Object,MFC的句柄变量存储一个有效句柄。

  CDC(设备描述表类)的创建有所不同,在后面的2.3节会具体说明CDC及其派生类的创建和使用。

  当然,可以在MFC Object的构造函数中创建相应的Windows对象,MFC的GDI类就是如此实现的,但从实质上讲,MFC Object的创建和Windows Object的创建是两回事。

  从转换上比较

  可以从一个MFC Object得到对应的Windows Object的句柄;一般使用MFC Object的成员函数GetSafeHandle得到对应的句柄。

  可以从一个已存在的Windows Object创建一个对应的MFC Object; 一般使用MFC Object的成员函数Attach或者FromHandle来创建,前者得到一个永久性对象,后者得到的可能是一个临时对象。

  从使用范围上比较

  MFC Object对系统的其他进程来说是不可见、不可用的;而Windows Object一旦创建,其句柄是整个Windows系统全局的。一些句柄可以被其他进程使用。典型地,一个进程可以获得另一进程的窗口句柄,并给该窗口发送消息。

  对同一个进程的线程来说,只可以使用本线程创建的MFC Object,不能使用其他线程的MFC Object。

  从销毁上比较

  MFC Object随着析构函数的调用而消失;但Windows Object必须由相应的Windows系统函数销毁。

  设备描述表CDC类的对象有所不同,它对应的HDC句柄对象可能不是被销毁,而是被释放。

  当然,可以在MFC Object的析构函数中完成Windows Object的销毁,MFC Object的GDI类等就是如此实现的,但是,应该看到:两者的销毁是不同的。

  每类Windows Object都有对应的MFC Object,下面用表格的形式列出它们之间的对应关系,如表2-1所示:

  表2-1 MFC Object和Windows Object的对应关系

  表2-1中的OBJECT分以下几类:

  描述Windows句柄MFC Object

  窗口HWNDCWnd and CWnd-derived classes

  设备上下文HDCCDC and CDC-derived classes

  菜单HMENUCMenu

  笔HPENCGdiObject类,CPen和CPen-derived classes

  刷子HBRUSHCGdiObject类,CBrush和CBrush-derived classes

  字体HFONTCGdiObject类,CFont和CFont-derived classes

  位图HBITMAPCGdiObject类,CBitmap和CBitmap-derived classes

  调色板HPALETTECGdiObject类,CPalette和CPalette-derived classes

  区域HRGNCGdiObject类,CRgn和CRgn-derived classes

  图像列表HimageLISTCimageList和CimageList-derived classes

  套接字SOCKETCSocket,CAsynSocket及其派生类

  Windows对象,

  设备上下文对象,

  GDI对象(BITMAP,BRUSH,FONT,PALETTE,PEN,RGN),

  菜单,

  图像列表,

  网络套接字接口

  从广义上来看,文档对象和文件可以看作一对MFC Object和Windows Object,分别用CDocument类和文件句柄描述。

  后续几节分别对前四类作一个简明扼要的论述。

  Windows Object

  用SDK的Win32 API编写各种Windows应用程序,有其共同的规律:首先是编写WinMain函数,编写处理消息和事件的窗口过程WndProc,在WinMain里头注册窗口(Register Window),创建窗口,然后开始应用程序的消息循环。

  MFC应用程序也不例外,因为MFC是一个建立在SDK API基础上的编程框架。对程序员来说所不同的是:一般情况下,MFC框架自动完成了Windows登记、创建等工作。

  下面,简要介绍MFC Window对Windows Window的封装。

  Windows的注册

  一个应用程序在创建某个类型的窗口前,必须首先注册该“窗口类”(Windows Class)。注意,这里不是C++类的类。Register Window把窗口过程、窗口类型以及其他类型信息和要登记的窗口类关联起来。

  “窗口类”的数据结构

  “窗口类”是Windows系统的数据结构,可以把它理解为Windows系统的类型定义,而Windows窗口则是相应“窗口类”的实例。Windows使用一个结构来描述“窗口类”,其定义如下:

  typedef struct _WNDCLASSEX {

  UINT cbSize; //该结构的字节数

  UINT style; //窗口类的风格

  WNDPROC lpfnWndProc; //窗口过程

  int cbClsExtra;

  int cbWndExtra;

  HANDLE hInstance; //该窗口类的窗口过程所属的应用实例

  HICON hIcon; //该窗口类所用的像标

  HCURSOR hCursor; //该窗口类所用的光标

  HBRUSH hbrBackground; //该窗口类所用的背景刷

  LPCTSTR lpszMenuName; //该窗口类所用的菜单资源

  LPCTSTR lpszClassName; //该窗口类的名称

  HICON hIconSm; //该窗口类所用的小像标

  } WNDCLASSEX;

  从“窗口类”的定义可以看出,它包含了一个窗口的重要信息,如窗口风格、窗口过程、显示和绘制窗口所需要的信息,等等。关于窗口过程,将在后面消息映射等有关章节作详细论述。

  Windows系统在初始化时,会注册(Register)一些全局的“窗口类”,例如通用控制窗口类。应用程序在创建自己的窗口时,首先必须注册自己的窗口类。在MFC环境下,有几种方法可以用来注册“窗口类”,下面分别予以讨论。

  调用AfxRegisterClass注册

  AfxRegisterClass函数是MFC全局函数。AfxRegisterClass的函数原型:

  BOOL AFXAPI AfxRegisterClass(WNDCLASS *lpWndClass);

  参数lpWndClass是指向WNDCLASS结构的指针,表示一个“窗口类”。

  首先,AfxRegisterClass检查希望注册的“窗口类”是否已经注册,如果是则表示已注册,返回TRUE,否则,继续处理。

  接着,调用::RegisterClass(lpWndClass)注册窗口类;

  然后,如果当前模块是DLL模块,则把注册“窗口类”的名字加入到模块状态的域m_szUnregisterList中。该域是一个固定长度的缓冲区,依次存放模块注册的“窗口类”的名字(每个名字是以“\n\0”结尾的字符串)。之所以这样做,是为了DLL退出时能自动取消(Unregister)它注册的窗口类。至于模块状态将在后面第9章详细的讨论。

  最后,返回TRUE表示成功注册。

  调用AfxRegisterWndClass注册

  AfxRegisterWndClass函数也是MFC全局函数。AfxRegisterWndClass的函数原型:

  LPCTSTR AFXAPI AfxRegisterWndClass(UINT nClassStyle,

  HCURSOR hCursor, HBRUSH hbrBackground, HICON hIcon)

  参数1指定窗口类风格;

  参数2、3、4分别指定该窗口类使用的光标、背景刷、像标的句柄,缺省值是0。

  此函数根据窗口类属性动态地产生窗口类的名字,然后,判断是否该类已经注册,是则返回窗口类名;否则用指定窗口类的属性(窗口过程指定为缺省窗口过程),调用AfxRegisterCalss注册窗口类,返回类名。

  动态产生的窗口类名字由以下几部分组成(包括冒号分隔符):

  如果参数2、3、4全部为NULL,则由三部分组成。

  “Afx”+“:”+模块实例句柄”+“:”+“窗口类风格”

  否则,由六部分组成:

  “Afx”+“:”+模块实例句柄+“:”+“窗口类风格”+“:”+光标句柄+“:”+背景刷句柄+“:”+像标句柄。比如:“Afx:400000:b:13de:6:32cf”。

  该函数在MFC注册主边框或者文档边框“窗口类”时被调用。具体怎样用在5.3.3.3节会指出。

  隐含的使用MFC预定义的的窗口类

  MFC4.0以前的版本提供了一些预定义的窗口类,4.0以后不再预定义这些窗口类。但是,MFC仍然沿用了这些窗口类,例如:

  用于子窗口的“AfxWnd”;

  用于边框窗口(SDI主窗口或MDI子窗口)或视的“AfxFrameOrView”;

  用于MDI主窗口的“AfxMDIFrame”;

  用于标准控制条的“AfxControlBar”。

  这些类的名字就 是“AfxWnd”、“AfxFrameOrView”、“AfxMdiFrame”、 “AfxControlBar”加上前缀和后缀(用来标识版本号或是否调试版等)。它们使用标准应用程序像标、标准文档像标、标准光标等标准资源。为了使用这些“窗口类”,MFC会在适当的时候注册这些类:或者要创建该类的窗口时,或者创建应用程序的主窗口时,等等。

  

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/dianzi/2713936.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-08-17
下一篇 2022-08-17

发表评论

登录后才能评论

评论列表(0条)

保存