Win32中安全的子類化 (1)
全域子類化
全域子類化類似於執行個體子類化。應用程式通過調用函數SetClassLong對一個視窗類別進行全域子類化,就象在執行個體子類化中一樣,應用程式同樣需要子類化函數的地址,並且這個子類化函數必須在應用程式中或DLL的模組定義檔案中匯出。
要全域子類化一個視窗類別,應用程式必須擁有一個該類的視窗執行個體。想要獲得該類的視窗執行個體,大多數應用程式採取建立一個屬於將要被全域子類化的視窗類別的視窗的方法,當應用程式要移除子類化,也必須有一個視窗控制代碼,該控制代碼應該是屬於應用程式要子類化的視窗類別的,因此,為此而專門建立並儲存一個視窗是個不錯的辦法。如果應用程式需要建立它所要子類化的視窗類別的視窗執行個體,這個視窗執行個體通常應該是不可見的。在擁有了一個正確類型的視窗控制代碼之後,應用程式可以使用該視窗控制代碼、GCL_WNDPROC 標誌(在WINDOWS.H 中有定義)和新子類化函數的地址作為參數調用函數SetClassLong,該函數返回一個DWORD值,該值是該視窗類別的原視窗過程地址。原視窗過程地址在全域子類化中的用處和在執行個體子類化中一樣,視窗訊息也象在執行個體子類化中一樣通過調用函數CallWindowProc傳遞給原視窗過程。應用程式可以通過再次調用SetClassLong函數來從視窗類別移除子類化,這時需通過傳遞參數是原視窗過程地址、GCL_WNDPROC 標誌和被子類化的視窗類別的視窗執行個體控制代碼。全域子類化一個控制項的應用程式必須在應用程式結束時移除所做的子類化。
下面的代碼示範了全域子類化一個編輯框控制項以及為它移除子類化:
LONG FAR PASCAL SubClassFunc(HWND hWnd,UINT,Message,WORD wParam,LONG lParam);
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)