正确还原子类化的窗体,子类化正确还原

正确还原子类化的窗体,子类化正确还原

大家在还原子类化时一般都喜欢用以下这种方法

注: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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值