原文连接:http://hi.baidu.com/workerwork/blog/item/08bf460f48b949296159f353.html
【转载文章只是为了做个标记,以备参考,顺便激励一下自己,争取也能写出好文章出来】
窗口子类化和超类化技术的应用
在讲述窗口的子类化和超类化之前,我们必须 先了解windows窗口类的概念。windows的窗口类 是windos 用来创建窗口的依据之一,每个窗口 必然属于某个窗口类。窗口类是一个窗口模板,包 含一个窗口所具有的部分窗口属性。编写一个windows程序时,首先要做的工作就是注册一个窗 口类,然后基于此注册的窗口类创建一个新的窗 口。在 windows平台中,注册窗口类的函数是 RegisterClass和 RegisterClassEX, 其 中 RegisterClassEx是推荐使用的函数,使用这个函数注册窗 口类时,需要先填写一个 WNDCLASS结构。这 个结构实际上反映了一个窗口类的特征,一个窗口 类有本类所有窗口公用的类属性、窗口函数、类图 标和小图标、类鼠标、窗口背景刷、类菜单,当然还 有类名。除此之外,每个类还有一定大小的类存储
区,可以用来存储该类的公共数据。 每一个创建的窗口都有一个窗口函数,其地址 由结构的 wndclASS参数lpfnWndProc设定, 该窗口函数处理对应于该窗口类的所有实例的消 息。当创建一个窗口时,windows 将分配一个内存 块,用来存放与该窗口相关的信息,并将参数 lpfnWndClass 从窗口类内存块拷贝到该内存块中。当消 息被分发到窗口时, windows 检查该窗口中内存块 中的 lpfnWndClass值,并调用该内存块地址上的窗 口函数。
一个窗口的行为主要取决于它的窗口函数,如 果能够改变一个窗口的窗口函数,使它指向自己写 的某个函数,那就意味着发给这个窗口的各种消息 将由我们自己写的这个函数来处理。 子 类化一个窗口,实际上就是改变窗口内存块 中的窗口函数的地址,使其指向用户自定义的新的 窗口函数入口,以实现用户希望的窗口特性。 超类化则是利用原来的那个窗口类的某些特 征,改变它另外的一些特征,包括窗口函数,重新注 册一个新的窗口类。 超类化和子类化的共同之处就是,这两种方法 都是从一个已经存在的窗口类产生新的窗口或窗 口类的方法,新的窗口或窗口类具有原来的窗口类 的某些特征,也具有一些新增的特征。但子类化是 从窗口的角度出发的,而超类化是从窗口类的角度 出发的。
窗口子类化技术最大的特点就是能够截取eindows的消息。一但用户自定义的窗日函数截取传向原窗口函数的消息,就可以对被截取的消息进行如下处理:
.将其传给原来的窗口函数。这是对大多数消息应该采取的措施,因为了类通常只对原来的窗口特性作少量的修改。
.截取该消息,阻止其向原窗口函数发送。
.修改该消息,修改完毕以后再向原窗口函数发送。
GetWindowLong SetWindowLong
在Windows编程中,使用窗子类化技术,可以方便地达到改变一个窗日的特性的日的。但子类化也存在其局限性。实际上,了类化的概念是针对一个己经创建的窗口来谈的,所以修改窗口函数是在窗口创建之后进行的,在窗口创建期间的消息无法捕获,也就无法处理。另外有些窗日的特性与窗日类本身的属性有关。比如如果一个窗日类没有CS_ DBLCLKS属性的话,那么要通过了类化这些窗u达到处理WM_ LBUTTOIVDBLCLK消息的日的。对于了类化的以上局限性,可以通过窗口的超类化技术来消除。实际上超类化可以完全实现了类化的功能。
超类化需要注册一个新的窗日类,达到改变窗日类的各种特征的目的。超类化实现的简单过程是获得一个己经存在的窗日类的特征,然后改变这些特征,最后重新注册一个窗日类。具体的步骤如下:
①定义一个类型为WNDCLASSEX的变量。因为需要注册新的窗日类,定义这个变量是必要的。
②调用GetClasslnfoEx函数得到希望超类化的那个窗口类的信息。
③改变窗口类的基本特征,显然窗口类名和模块句柄hlnstance是必须改变的。注意如果需要改变窗口类的窗口函数的话,在改变窗口函数之前应该保存原来的窗口函数,井且在新的窗日函数中把不需要处理的消息传递给原来的窗口函数,以保留原窗口类的一些特征。
④利用修改后的WIVDCLASSEX变量,调用RegisterClassEX函数重新注册一个新的窗u类。
⑤创建这个新窗日类的一个窗日实例。
(1)用MFC Application Wizard新建一个MDl程序SuperClassingo
(2)利用ClassWizard建一个从 CWnd类派生的新类CDblClkWnd。添加MDl客户窗口对左键双击的处理函数:
(3)重新注册一个窗口类,进行超类化。
BOOL CDblClkWnd::RegisterNewClass()
{
WNDCLASS wc;
if(!GetClassInfo(NULL,"MDIClient",&wc))
return FALSE;
wc.style=SC_DBLCLKS;
wc.lpszClassName="DBLCLCMDIClient";修改名字
return RegisterClass(&wc);
}
在APP类的InitInstance函数前创建主框架的代码前调用上面的注册新窗口的类的代码
if(!CDblClkWnd::RegisterNewClass())
return false;
在使用CreateWindowEx创建MDI客户窗口的时候,把原来的窗口类MDIClient改为DB LCLCMDIClient
在主窗口中添加变量CDblClkWnd m_client,在主窗口的OnCreate中对MDIClient进行子类化。在OnDestroy中进行反子类化。
pclient.SuhclassWindow(phWndMDlClient);
m client.UnsubclassWindow();//反子类化
窗口子类化和超类化技术的应用
最新推荐文章于 2019-03-29 11:19:00 发布