正確還原子類化的窗體,子類化正確還原

正確還原子類化的窗體,子類化正確還原

大家在還原子類化時一般都喜歡用以下這種方法

注:pWindowProc是你的窗體函數指針, m_hWnd是窗體句柄

//保存子類化之前的窗體指針,用下面兩種方法保存
LONG lwndProc = ::GetWindowLong(m_hWnd, GWL_WNDPROC);

LONG lwndProc = ::SetWindowLong(m_hWnd, GWL_WNDPROC, pWindowProc);



然後還原時會這樣
::SetWindowLong(m_hWnd, GWL_WNDPROC, lwndProc );//還原

 其實這樣是對的,只是這個窗體必須只有你一個程序進行了子類化,這樣還原纔行。
假如你的程序是B 有A程序是別人的
A先子類化窗體,接着是你的B子類化窗體,用上面的方法得到的指針將是A的
不信你可以試試,得到的窗體過程指針就是A用SetWindowLong設置進去的pWindowProc
如果還原時,A先還原(A還原肯定是原始的窗體指針啦),然後你的B再去還原
結果將把A的窗體指針設進去,這樣窗體原始指針將得不到真正的還原.
過程如下:
原始指針地址是0x00000001 A程序將要設的窗體指針地址是0x00000002
   B程序將要設的是0x00000003
   
   A先子類化用GetWindowLong得到原指針(0x00000001)保存,
   將0x00000002用SetWindowLong設進去,
   還原時是0x00000001

   B窗體再去子類化用GetWindowLong得到原指針(0x00000002)保存,
   將0x00000003用SetWindowLong設進去,
   還原時是0x00000002

    如果A先退出,A在退出時已還原了窗體原始指針(0x00000001),結果在B還原時,又將
    指針改成了0x00000002,表面看起來還原啦,其實沒有還原
    如果0x00000002指向的內存在還好,不存在就會崩啦

    最關鍵的是在子類化和子類化還原時都沒辦法做到誰先誰後,這都是操作系統控制的。
    但目的都是子類化窗體,並在退出時還原到原始窗體指針(0x00000001)
    正確的做法是在WM_NCDESTROY裏還原子類化,切記不要在HOOK過程的WM_NCDESTROY
    中還原,要在子類化過程的WM_NCDESTROY消息中處理,MFC的做法也是這樣的,不信你
    可以去看MFC中CWnd代碼

代碼如下:
更多代碼:http://bbs.panshsoft.com/read.php?tid=2216
    //如果調用這個函數,就不要再調用
//CallWindowProc啦

 virtual LRESULT NcDestroy()
 {
 WNDPROC wndproc = NULL;
 LRESULT lReturnValue = 1;
 //m_WndOldProc是用GetWindowLong子類化前保存的窗體地址
 if(NULL == m_WndOldProc) return 0;

 wndproc = (WNDPROC)::GetWindowLong(m_hWnd, GWL_WNDPROC);

 //pWindowProc是用SetWindowLong(m_hWnd, GWL_WNDPROC,pWindowProc)設進去的
 if(wndproc == (WNDPROC)pWindowProc/*你窗體的指針*/)
 {
  ::SetWindowLong(m_hWnd, GWL_WNDPROC, (LONG)m_WndOldProc);

  lReturnValue = ::CallWindowProc(m_WndOldProc, m_hWnd,
      WM_NCDESTROY, 0, 0);
  m_WndOldProc = NULL;
 }
 else
 {
  lReturnValue = ::CallWindowProc(m_WndOldProc, m_hWnd,
        WM_NCDESTROY, 0, 0);

  if(wndproc == (WNDPROC)::GetWindowLong(m_hWnd, GWL_WNDPROC))
  {
   ::SetWindowLong(m_hWnd, GWL_WNDPROC, (LONG)m_WndOldProc);
   m_WndOldProc = NULL;
  }
 }

 return lReturnValue;
}

 


代碼說明
先判斷該窗口的窗體過程指針是否發生過變動,
如果沒有的話是最好的,趕緊撤銷子類化,
再把消息傳遞給之前窗口過程,然後退出

如果發生過變動,那麼也就是說有別程序在你子類化以後又進行了子類化,
而現在又把WM_NCDESTROY傳給了你。
所以把消息繼續往前傳,
如果窗體過程指針(WNDPROC)又發生了改變,
說明之前的某個窗口過程已經作了處理,
就不需要再進行撤銷子類化的操作了。

http://bbs.panshsoft.com/read.php?tid=2216


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章