窗口子類化和超類化技術的應用

原文連接: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();//反子類化

發佈了60 篇原創文章 · 獲贊 32 · 訪問量 44萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章