[翻译]Win32中安全的子类化 (5)

  Win32中安全的子类化 (1)

超类化

子类化一个窗口类,导致原本属于窗口过程的消息被发送至子类化函数,然后该子类化函数再把消息传递给原窗口过程,而超类化(也被称作窗口类克隆)是创建一个新的窗口类。这个新窗口类使用一个已经存在的窗口类的窗口过程,来为它自己添加和已经存在的窗口类一样的功能,超类化是基于其它窗口类的――也被称为基类。基类常常是Windows预定义的控件类,但它也可以是任何其它窗口类。

注意   不要超类化滚动条控件类,因为Windows 使用该类名来为滚动条提供标准的行为。

超类化拥有它自己的窗口过程――超类化过程,它能起和子类化函数一样的作用。超类化过程可以对消息实施三种动作: (1)直接将消息传递给原窗口过程(2)在传递给原窗口过程前修改消息。 (3)不在往下传递消息。超类化可以在把消息传递给原窗口过程之前、之后或两者都有的情况下对消息进行操作。

和子类化函数不一样的是,一个超类化过程也可以从Windows接收创建消息(例如WM_NCCREATE, WM_CREATE 之类的),超类化可以处理这些消息,但它必须把这些消息传递给原基类窗口过程,这样基类窗口过程才能进行初始化操作

应用程序调用函数GetClassInfo来使一个超类化基于一个基类。函数GetClassInfo使用从基类的WNDCLASS结构得来的值填充一个新WNDCLASS结构。然后超类化基类的应用程序把新WNDCLASS结构的hInstance域的值设置成应用程序自己的实例句柄,同时也必须把lpszClassName的值设置成它要给该超类化的新名称。如果基类拥有一个菜单,超类化该基类的应用程序必须提供一个新菜单,该新菜单必须和基类的菜单拥有相同的菜单标识。如果该超类化打算处理WM_COMMAND消息的,并且不再把该消息传递给基类的窗口过程,那么菜单的标识可以不必和基类的一样。函数GetClassInfo不会返回WNDCLASS结构中域 lpszMenuName, lpszClassName, hInstance的值。

最后一个必须在超类化的WNDCLASS结构中设置的是域lpfnWndProc,函数GetClassInfo用原窗口过程的地址填充它。应用程序必须保存这个地址,以便能用函数CallWindowProc把消息传递给基类的窗口过程。应用程序要在WNDCLASS结构中把该地址值设置成它的超类化过程的地址。这个地址并不是个过程实例地址,因为函数RegisterClass才能得到过程实例地址。应用程序可以修改WNDCLASS结构中其它域的值,以便符合应用程序的需要。

应用程序可以往窗口类附加字节和窗口实例附加字节后添加内容,这是因为它注册了一个新窗口类。当应用程序做这件事时,必须遵从两个规则: (1) 原类附加字节和窗口实例附加字节不能被子类化覆盖,这和在实例子类化与全局子类化中的原因一样。(2) 如果应用程序因自身需要为窗口类或窗口实例添加了附加字节,它在引用这些附加字节时,必须保持是相对于基类所使用的附加字节数来引用的。而且因为某个版本的基类所使用的附加字节数可能会与下一个版本不同,所以超类化自己的附加字节的起始偏移也因基类版本不同而不同。

当填充完WNDCLASS结构后,应用程序应该调用函数RegisterClass来注册新的窗口类,现在,就可以创建并使用属于该新窗口类的窗口实例了。

应用程序通常是在Win16环境下使用超类化,因为在Win16环境下全局子类化是令人沮丧的。现在在Win32下,全局子类化不再令人失望,所以超类化就不再那么具有吸引力了。但在你的应用程序要改变一些窗口的行为,而这些窗口又只是从一个系统窗口类所创建的所有窗口中的一部分时,你仍然可以发现使用超类化是很有用的,相反,对从一个系统窗口类所创建的所有窗口都有效,那是全局子类化的功能。

总结

子类化是个强大的技术,而且在Win32中的使用也没有发生什么特别重大的改变,唯一的比较主要的变化是你不能再属于另一个进程的窗口或窗口类,虽然有方法可以绕过这个限制,如果你确实需要这种能力,我还是建议你把你的应用程序移植到OLE,这比仍然依赖子类化更好。

好了,至此整篇文章都翻译完了(终于赶在放假前弄完了),在Win32中安全的子类化(1)中,提供了本文的英语原文的链接,由于本人时间、水平有限,所以欢迎大家指正文中的错误和疏漏之处,谢谢!

posted on 2006-01-25 11:08  I.AM.Wright  阅读(1236)  评论(0编辑  收藏  举报

导航