farproc's blog

理性爱国

说说安全子类

作者:袁晓辉    文章来源:www.farproc.com   更新时间:2005-5-25

说说安全子类

说起“窗口子类化”(Subclass Window),估计大家都不陌生吧?不就是SetWindowLong (hwnd, GWL_WNDPROC, NewProc)嘛,如果还有什么要说的话,那就是为了兼容3264Windows,换用SetWindowLongPtr吧。就这么简单吗?其实越是看起来简单的东西,往往越容易被误用,我们来看一个例子:

 

 

这看似没有问题的代码真的可靠吗?未必!!

想想吧,如果在我们做“... 一些操作 ...”的时候,又有一个程序子类了该窗口(hwnd)会怎么样?那个子类会用它的procedure替换我们的NewWndProc,并保存我们的NewWndProc指针。这时windows消息会先经过它的procedure,到我们的NewWndProc,然后我们传递给OldWndProc。当我们替换回原来的窗口过程时发生了好么?我们恢复了OldWndProcwindows消息直接传递给了OldProc,而不会经过后来的那个子类的procedure了,我们一下子取消了两个子类!一个是我们添加的,一个是在我们之后添加的。如果后来的那个子类的procedure在堆上分配了内存,准备在收到WM_DESTROY时释放,那么它永远都收不到这个消息,这块内存也就泄漏了……

不要以为子类的添加和删除是一个“入栈、出栈”的操作(你只能操作栈顶也就是最后入栈的元素)。如果你想要删除你的子类,而你窗口procedure并没有位于子类链的最顶端的话,你就不能安全地删除你的子类。如果你在这时移除了你的子类并恢复了你所保存的旧prodecure的话,那么在你后面添加的子类都被你从子类链上“摘掉”了。安全的做法是你必须等待,直到可以安全删除你的子类时再删除,并且在等待期间把收到的任何消息传递给前一个procedure处理。

这是很令人讨厌的,所以,微软为我们准备了好用的函数来帮我们完成这些操作。用SetWindowsSubclass(位于Windows XP自带的CommCtl32.dll 6.0版中。 后面的几个函数也一样) 可以很方便地添加一个子类,它会在内部保存前一个子类的必要信息,传递你指定的“参考数据”到子类的procedure。用DefSubclassProc 传递消息到前一个子类。完成操作时,用RemoveWindowSubclass 删除你添加的子类本身,这个函数会自动做好所有的处理,你不必担心你的procedure是否位于子类链的顶端。但是有一点同样需要注意,你必须在被窗口(hwnd)销毁前删除你的子类。

 

 

微软为我们提供的这中“安全”子类的机制非常棒,目前用的人却不是很多,可能是因为它只能在XP系统上用的缘故吧。但不管如何,我们还是关心一下新技术的好,说不定哪天能用得着。

 

 参看这里:子类化控件的新方法

 参看这里:子类化控件的新方法

 

注:本文部分内容参考这里

阅读更多
文章标签: windows 微软 xp
个人分类: Windows C++编程
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭