人們看到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