正確還原子類化的窗體,子類化正確還原
大家在還原子類化時一般都喜歡用以下這種方法
注: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