人们看到LockWindowUpdate“锁定的窗口将不能绘制自己”的行为,就用它来作为WM_SETREDRAW消息的偷懒的使用方式,尽管发送一个WM_SETREDRAW消息不不比调用LockWindowUpdate更麻烦。只是多打20来个字符,而且如果使用<windows.h>中的SetWindowRedraw宏的话还少会一半。
不使用
|
LockWindowUpdate(hwnd)
|
代而使用
|
SendMessage(hwnd, WM_SETREDRAW, FALSE, 0) or SetWindowRedraw(hwnd, FALSE)
|
不使用
|
LockWindowUpdate(NULL)
|
代而使用
|
SendMessage(hwnd, WM_SETREDRAW, TRUE, 0) or SetWindowRedraw(hwnd, TRUE)
|
就像我们在前面所说的,同一时间系统中只能有一个窗口的更新被锁定。如果你调用LockWindowUpdate的目的仅仅是防止窗口重绘,比如因为你在更新这个窗口,在你的更新完成前,不希望它不停的刷新,那么请直接禁止窗口的重绘。如果你使用了LockWindowUpdate,将引来无数下面的问题。
首先,如果另一个什么程序也以同样错误的方式使用LockWindowUpdate,那么你们中会有一个人失败。首先调用LockWindowUpdate的程序将会成功,第二个调用的程序将会失败。现在你准备怎么办?你的窗口不会被锁定。
其次,如果你锁定了自己的窗口更新,这时用户切换到另一个程序,并试图拖拽一个对象(或甚至只是尝试移动一下那个窗口),那一个LockWindowUpdate将会失败,于是用户遇到了一个由于某种神秘原因拖放失效的情形。然后,10秒钟后,一切功能又运作作正常。“愚蠢的烂Windows”用户嘀咕道。
反过来说,如果你在一个拖放或是窗口移动的过程中准备调用LockWindowUpdate,那么你的调用就会失败。
这只是更一般意义上,使用全局状态来处理局部情况的编程错误中,比较具体的例子。当你想禁止自己的一个窗口的重绘时,你不会希望这会影响到系统中的其它窗口。更新自己的窗口是一个局部情况,但是你使用了全局状态(被锁定更新的窗口)来维持它。
我可以预料到有人会说:“那么,窗口管理器应当阻止人们在一个非拖放操作中锁定窗口更新。”问题是,窗口管理器怎么知道这个?它只是知道发生了什么事情,但不知道为什么发生。一个程序到底是由于懒于使用WM_SETREDRAW消息而使用LockWindowUpdate?还是为了响应引发拖放操作的用户输入?这里没办法说“用户鼠标按键压下了”,因为用户可能用基于键盘的理论上和拖放等价的操作(例如使用方向键来改变窗口尺寸)。基本上这个问题很难于解决,除非计算机能更多一点对让他做的事情的猜想。
下一回是对LockWindowUpdate的最终评论。
LockWindowUpdate系列5:关于LockWindowUpdate的最终评论
现在大家了解了LockWindowUpdate的设计意图,我现在将要告诉大家你们为什么不应当使用这个函数,甚至不是因为其设计意图的缘因。
这需要回到LockWindowUpdate被创造出来的历史环境。回到16位Windows(特别是Windows 3.1)的时代。在那时,内存还是很昂贵的,显示驱动功能也很有限。还没有DirectX,没有AlphaBlend函数。你所拥有的一切就是一块屏幕缓冲区。LockWindowUpdate函数允许你接管这个屏幕缓冲区中对应一个窗口的部分,以得以在不需窗口知道的情况下应用自己特别的效果。
Windows 3.1距今已经十年多了,在这期间,我们有了DirectX覆盖、区域化窗口、分层窗口、alpha混合、桌面合成,种种我们在过去不曾拥有的绝妙图象特效。特别是这些美妙的分层窗口和区域化窗口,允许你做几乎所有你希望用LockWindowUpdate去做的事情。如果你希望在一个窗口边沿绘制高亮,你可以在其边沿放置一个区域化窗口。如果你希望在一个窗口上方绘制一个拖拽图片,你只需要创建一个分层窗口,并把它放置到目标窗口上方即可。使用的是分层窗口、一个区域及你想要的无论哪一种奇特的alpha通道,而将冗重的alpha混合和合成推给图象引擎来完成。更好的是,分层窗口可以伸展到拖拽经过的窗口以外,这是LockWindowUpdate无法完成的。(你可以在Windwos XP中看到这种特效,在资源管理器窗口中“全选”,并将整个选择内容在屏幕上拖拽。你将看到拖拽图像没有局限于拖拽经过的窗口边界。)
更甚者,在Vista的桌面窗口管理器(desktop window manager)令人惊奇的全新合成方式中,LockWindowUpdate更是不再值得使用。锁定一个特定窗口的更新还不算太成问题,因为桌面窗口管理器可以只是给你这个窗口的后台位图。但是如果你锁定了整个屏幕(我常见到人们这么做),桌面窗口管理器就需要将所有窗口合成到一个实际位图中,以便在你使用DCX_LOCKWINDOWUPDATE标志调用GetDCEx时可以返回给你。桌面窗口管理器通常是在DirectX和显示驱动加速的辅助下直接进行合成的,所有的合成结果通常是直接送到屏幕上,实际上根本不会存放在一个“合成后的”位图中。但是如果你锁定了屏幕,并请求一个屏幕的DC,桌面窗口管理器只得模拟老式的行为,使得你可以访问一个代表了假如根本没有合成这回事的情况下,你“应当得到”的东西。这并不轻松!
尾声。我并不清楚这个系列是否成功。我的目标只是帮助人们更有效的使用LockWindowUpdate,并在LockWindowUpdate不适于一个工作时指导他们转向其它的替代物。换句话说,这是一篇关于LockWindowUpdate的文章,不是函数文档。我试图让我的表达显得轻松一些,但我估计我的幽默并不好笑,人们只是用他们来做为否定注解的跳板。
特别感谢那些把这个系列用来作为一个抱怨文档的机会的人们。我的意思是,咄,如果文档是完美的,我也大可不必写这么一个系列。不过这些人们往往只是看了函数说明那一页,而忽视了阅读所有文档。嘿,除了单纯的函数说明外,还有更多的文档哪!函数说明只是一个参考,你应当是在已经知道会发生什么,并只是需要微调一些细节时,才会到那里去看一下。真正的学习应当是从概览和文章中去进行。如果你想学习如何操作你的收音机,你不会上来就看电路图的。
我认为当Ronald D. Moore说“听播客时你必须有足够的忍耐力”时,他一定是在搞什么鬼。
LockWindowUpdate系列1:LockWindowUpdate的行为?
LockWindowUpdate系列2:LockWindowUpdate是打算如何使用的?
LockWindowUpdate系列3:什么样的操作中应当使用LockWindowUpdate?
LockWindowUpdate系列4:什么样的操作中不应当使用LockWindowUpdate?
LockWindowUpdate系列5:关于LockWindowUpdate的最终评论
原文出处:http://blogs.msdn.com/oldnewthing/archive/2007/02/19/1716211.aspx
原文出处:http://blogs.msdn.com/oldnewthing/archive/2007/02/20/1726880.aspx
原文出处:http://blogs.msdn.com/oldnewthing/archive/2007/02/21/1735472.aspx
原文出处:http://blogs.msdn.com/oldnewthing/archive/2007/02/22/1742084.aspx
原文出处:http://blogs.msdn.com/oldnewthing/archive/2007/02/23/1747713.aspx