[翻译]Win32中安全的子类化 (4)
全局子类化
全局子类化类似于实例子类化。应用程序通过调用函数SetClassLong对一个窗口类进行全局子类化,就象在实例子类化中一样,应用程序同样需要子类化函数的地址,并且这个子类化函数必须在应用程序中或DLL的模块定义文件中导出。
要全局子类化一个窗口类,应用程序必须拥有一个该类的窗口实例。想要获得该类的窗口实例,大多数应用程序采取建立一个属于将要被全局子类化的窗口类的窗口的方法,当应用程序要移除子类化,也必须有一个窗口句柄,该句柄应该是属于应用程序要子类化的窗口类的,因此,为此而专门创建并保存一个窗口是个不错的办法。如果应用程序需要创建它所要子类化的窗口类的窗口实例,这个窗口实例通常应该是不可见的。在拥有了一个正确类型的窗口句柄之后,应用程序可以使用该窗口句柄、GCL_WNDPROC 标志(在WINDOWS.H 中有定义)和新子类化函数的地址作为参数调用函数SetClassLong,该函数返回一个DWORD值,该值是该窗口类的原窗口过程地址。原窗口过程地址在全局子类化中的用处和在实例子类化中一样,窗口消息也象在实例子类化中一样通过调用函数CallWindowProc传递给原窗口过程。应用程序可以通过再次调用SetClassLong函数来从窗口类移除子类化,这时需通过传递参数是原窗口过程地址、GCL_WNDPROC 标志和被子类化的窗口类的窗口实例句柄。全局子类化一个控件的应用程序必须在应用程序结束时移除所做的子类化。
下面的代码演示了全局子类化一个编辑框控件以及为它移除子类化:
FARPROC lpfnOldClassWndProc;
HWND hEditWnd;
//
// Create an edit control and subclass it.
// Notice that the edit control is not visible.
// Other details of this particular edit control are not important.
//
hEditWnd = CreateWindow("EDIT", "EDIT Test",
WS_CHILD,
0, 0, 50, 50,
hWndMain,
NULL,
hInst,
NULL);
lpfnOldClassWndProc = (FARPROC)SetClassLong(hEditWnd, GCL_WNDPROC, (DWORD)SubClassFunc);
.
.
.
//
// To remove the subclass:
//
SetClassLong(hEditWnd, GWL_WNDPROC, (DWORD) lpfnOldClassWndProc);
DestroyWindow(hEditWnd);
潜在的缺陷
全局子类化具有和实例子类化一样的限制,除非明确知道原窗口过程如何使用窗口类和窗口实例的附加字节,否则应用程序不应尝试去使用它们。如果数据必须和一个窗口相关联,可以象实例子类化中介绍的一样,使用窗口属性列表。
在Win32中, 全局子类化不会对任何其它进程中的窗口类或从这些类创建的窗口实例生效,这对于Win16环境是个重大的变化。在系统中,Windows分别为每个Win32进程单独保存窗口类的信息,可以参见MSDN中的技术文章Window Classes in Win32来了解Windows在这方面的细节。目前全局子类化不能对其它进程生效,这对开发人员来讲,是个有用的技术。在Win16中,全局子类化对被子类化的窗口类的每一个窗口实例都生效:不仅仅是属于执行了子类化操作的应用程序,还包括了属于整个系统的,这点让人感到失望。通常这是应用程序不想达到的效果,所以应用程序不得不使用更不方便,不好用的方法来改变从系统窗口类创建的窗口实例行为。而现在,在Win32中,使用全局子类化却是非常容易的。
Win32中安全的子类化 (5)
posted on 2006-01-24 16:28 I.AM.Wright 阅读(1296) 评论(0) 编辑 收藏 举报