[翻译]Win32中安全的子类化 (3)
实例子类化
SetWindowLong函数用来子类化一个窗口的一个实例。应用程序必须知道子类化函数的地址,子类化函数是这样一个函数:它用来接收从Windows发来的消息,并把消息传递给原窗口过程。子类化函数必须在应用程序中或DLL的模块定义文件中导出。
应用程序子类化窗口时,使用将要被子类化的窗口的句柄、GWL_WNDPROC标志(在WINDOWS.H中定义)以及新的子类化函数地址作为参数调用函数 SetWindowLong。函数SetWindowLong返回一个DWORD类型的值,它是窗口的原窗口过程地址,应用程序应该保存该地址以用于将截获的消息传递给原窗口过程,以及将来为窗口移除子类化之用。应用程序使用原窗口过程的地址以及Windows消息所使用的hWnd, Message, wParam和lParam参数调用函数CallWindowProc向原窗口过程传递消息。通常应用程序只是简单地把它从Windows接收来的数据传递给函数CallWindowProc。
应用程序同时需要原窗口过程地址来为窗口移除子类化。应用程序通过再次调用函数SetWindowLong来为窗口移除子类化,应用程序向函数传递原窗口过程地址、GWL_WNDPROC 标志以及已经被子类化的窗口的句柄。
下面的代码演示子类化一个编辑框控件以及为它移除子类化:
FARPROC lpfnOldWndProc;
HWND hEditWnd;
//
// Create an edit control and subclass it.
// The details of this particular edit control are not important.
//
hEditWnd = CreateWindow("EDIT", "EDIT Test",
WS_CHILD | WS_VISIBLE | WS_BORDER ,
0, 0, 50, 50,
hWndMain,NULL,hInst,NULL);
//
// Now subclass the window that was just Created.
//
lpfnOldWndProc = (FARPROC)SetWindowLong(hEditWnd,GWL_WNDPROC, (DWORD) SubClassFunc);
.
.
.
//
// Remove the subclass for the edit control.
//
SetWindowLong(hEditWnd, GWL_WNDPROC, (DWORD) lpfnOldWndProc);
//
// Here is a sample subclass function.
//
LONG FAR PASCAL SubClassFunc(HWND hWnd,
UINT Message,WPARAM wParam,LONG lParam)
{
//
// When the focus is in an edit control inside a dialog box, the
// default ENTER key action will not occur.
//
if ( Message == WM_GETDLGCODE )
return DLGC_WANTALLKEYS;
return CallWindowProc(lpfnOldWndProc, hWnd, Message, wParam,lParam);
}
潜在的缺陷
只要留意下面的保障规则,实例子类化通常是安全的。
当子类化一个窗口时,你必须了解谁在对窗口的行为负责,例如,Windows负责它所提供的所有控件的行为,而应用程序则对它自己定义的所有窗口负责。子类化可以作用在同一进程中的任何一个窗口上,但是,当一个应用程序子类化一个不属于它自己负责的窗口时,应用程序必须确保子类化函数不会破坏那个窗口原有的行为。由于应用程序并未控制那个窗口,它不应该依赖任何在未来很有可能会被窗口的拥有者改变的窗口信息。除非确切地知道窗口附加字节或窗口类附加字节的含义以及原窗口过程如何使用它们,否则一个子类化函数不应该使用它们。退一步说,即使应用程序了解关于窗口附加字节或窗口类附加字节的每一件事,除非应用程序负责这个窗口,否则也不要使用它们。如果一个应用程序使用了由另一个组件负责的窗口的窗口附加字节,当那个组件决定更新窗口并且改变附加字节的结构时,子类化过程很有可能会失败。正是因为这个原因,Microsoft 建议你不要子类化控件类,因为Windows负责着这些它所提供的控件,而且下一个版本的Windows可能会改变这些控件的外观。如果你的应用程序必须子类化一个Windows提供的控件,在新版本的Windows发布后,代码很可能也需要更新。
由于实例子类化发生在一个窗口被创建之后,应用程序子类化窗口无法向窗口添加任何附加字节,应用程序也许需要将被子类化的窗口的实例所需的所有数据保存在窗口的属性列表中。
SetProp函数可以把属性附加到一个窗口。应用程序使用窗口的句柄、一个标示属性的字符串和属性数据的句柄作为参数调用SetProp函数。数据的句柄通常从调用LocalAlloc或 GlobalAlloc函数获得。当应用程序要使用一个窗口的属性列表中的这些数据时,可以使用窗口的句柄和标示属性的字符串作参数调用GetProp函数,它返回用SetProp函数设置的数据的句柄。当应用程序不再需要这些数据或者当窗口将要被销毁时,应用程序必须使用窗口的句柄和标示属性的字符串作参数调用RemoveProp函数从属性列表中移除这些属性数据,该函数返回数据的句柄,然后应用程序使用该句柄调用函数LocalFree或函数GlobalFree。关于函数SetProp, GetProp和RemoveProp的更多信息,参见平台SDK文档。
当一个应用程序子类化一个已经被子类化过的窗口时,所有的子类化会被按照们被设置时的相反顺序移除。
Win32中安全的子类化 (4)
posted on 2006-01-20 15:15 I.AM.Wright 阅读(1776) 评论(3) 编辑 收藏 举报