• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            牽著老婆滿街逛

            嚴以律己,寬以待人. 三思而后行.
            GMail/GTalk: yanglinbo#google.com;
            MSN/Email: tx7do#yahoo.com.cn;
            QQ: 3 0 3 3 9 6 9 2 0 .

            LockWindowUpdate系列

            譯者:BalonFan
            原文:The Old New Thing




            LockWindowUpdate系列1:LockWindowUpdate的行為?

            對LockWindowUpdate可憐的誤解。
             
            這是關于LockWindowUpdate系列的第一篇。LockWindowUpdate的行為,它是用于做什么的,以及(可能更重要的是)它不是用于做什么。
             
            LockWindowUpdate做的事情其實很簡單。當一個窗口被“鎖定”,所有向它及其子窗口的繪制都會失敗。取代繪制操作的是,窗口管理器記住了應用程序試圖在窗口的哪一部分中進行繪制。當窗口“解鎖”后,這些區域被無效化,使得應用程序得到一個WM_PAINT消息,從而重新恢復了屏幕內容與應用程序認為應當在屏幕上顯示的內容之間的同步。
              
            大家已經在CS_SAVEBITS看到了“記錄在情形X有效時,應用程序試圖做的繪制,并在情形X不再有效時做無效處理”這樣的行為。在這種意義上,LockWindowUpdate做了同樣的簿記的工作。在你用一個CS_SAVEBITS窗口覆蓋鎖定的窗口時這個行為就會發生,只是這里不會保存什么數據。
             
            在文檔中明確的指出,同一時間只能有一個窗口被鎖定。同時這也可以由函數原型暗示得出。如果兩個窗口可以同時被鎖定,將無法可靠的使用LockWindowUpdate。當你做下面的事情時將會怎樣:
            LockWindowUpdate(hwndA); // 鎖定窗口A
            LockWindowUpdate(hwndB); // 將窗口B也鎖定
            LockWindowUpdate(NULL); // ???
             
            第三個對LockWindowUpdate的調用會做什么么?是把所有的窗口解鎖?還是只解鎖窗口A,或是只解鎖窗口B?不論你如何回答,都不可能讓下列的代碼可靠的使用LockWindowUpdate:
            void BeginOperationA()
            {
             LockWindowUpdate(hwndA);
             ...
            }
             
            void EndOperationA()
            {
             ...
             LockWindowUpdate(NULL);
            }
             
            void BeginOperationB()
            {
             LockWindowUpdate(hwndB);
             ...
            }
             
            void EndOperationB()
            {
             ...
             LockWindowUpdate(NULL);
            }
             
            設想BeginOperation開始了由異步行為觸發的某個操作。例如,假設操作繪制播放的反饋,因此開始于鼠標按下,并結束于鼠標釋放。
             
            現在假設仍在播放過程中時,操作B結束了。EndOperationB將會清理操作B,并調用LockWindowUpdate(NULL)。如果你假設這將解鎖所有窗口,那么就會破壞了操作A,因為它預期hwndA仍被鎖定。類似的,如果你提出應當只解鎖hwndA,那么不只操作A被破壞了,操作B也會被破壞(因為盡管操作B已經完成,hwndB仍被鎖定)。另一方面,如果你建議LockWIndowUpdate(NULL)應當解鎖hwndB,那么請考慮一下操作A先于B完成的情況。
             
            如果LockWindowUpdate同一時間能夠鎖定多于一個窗口,那么這個函數的原型就需要修改,以使得解鎖的操作可以知道那一個窗口正在被解鎖。有很多方法可以做到這一點,例如添加一個新的參數或是創建一個單獨的函數。
            // 方法A – 新參數
            // fLock = TRUE 鎖定, FALSE 解鎖
            BOOL LockWindowUpdate(HWND hwnd, BOOL fLock);
             
            // 方法B – 獨立函數
            BOOL LockWindowUpdate(HWND hwnd);
            BOOL UnlockWindowUpdate(HWND hwnd);
             
            但是這兩個都不是實際的情況,LockWindowUpdate函數同一時間只鎖定一個窗口。這樣做的原因在了解了LockWindowUpdate是用來做什么的之后會更加清晰





            LockWindowUpdate系列2:LockWindowUpdate是打算如何使用的?

            現在我們知道了LockWindowUpdate的行為。現在我們來看一下它是用于做什么的。
             
            事實上,LockWindowUpdate的設計意圖可以用一個詞表達:拖拽。但我們稍后再說到這個。
             
            LockWindowUpdate的目的是允許一個程序暫時的接管繪制窗口的工作。為了做到這個,你當然需要防止窗口函數(或其它任何人)進行他們正常的繪制活動;否則,兩處的代碼(正常繪制窗口的代碼和試圖接管繪制的代碼)會互相爭奪對窗口的控制,由于互不知道對方在做什么,最后得到的將是一團糟。
             
            但是,如果你已經鎖定了窗口的更新,那么如何才能在窗口上繪制呢?你可以在GetDCEx函數中使用DCX_LOCKWINDOWUPDATE標志。這個標志表示“即便是窗口已經鎖定,也讓我繪制到上面”。當然了,只有鎖定了這個窗口的代碼才能傳遞這個標志,否則又會引發LockWindowUpdate起初試圖解決的那類沖突。
             
            由于人們都很喜歡看表格,我制作了一個表格總結了當一個窗口被鎖定更新時發生了什么變化。
             
            正常行為
            更新被鎖定
            BeginPaint, GetDC,等等…
            繪制操作繪制到窗口上
            繪制操作沒有在窗口上繪出任何東西,但影響的區域被記錄下來以供后面無效化
            帶DCX_LOCKWINDOWUPDATE標志的GetDCEx
            (不要使用)
            繪制操作繪制到窗口上
              
            換句話說,當一個窗口更新被鎖定后,普通的DC獲取函數(BeginPaint及其伙伴)向窗口上繪制的能力將被剝奪,賦于了GetDCEx(DCX_LOCKWINDOWUPDATE)。注意,如果沒有窗口被鎖定更新,不要使用DCX_LOCKWINDOWUPDATE標志,這個標志的目的是指出“我就是那個調用了LockWindowUpdate的家伙,快放行!”
             
            窗口管理器有幾分像喜劇中的情節。你告訴守衛說“不許任何人進入這個房間。”一小時后你回來了,守衛不讓你進去。
            “對不起先生,我不能讓任何人進這個房間。”
            “但我就是那個告訴你不讓任何人進去的人呀。”
            “是的,先生,我是按照您的指示做的。任何人都不能進入這個房間。” 
            錯誤在于最初給守衛下達的命令。你應當說:“除了我以外,任何人都不允許進入這個房間。” DCX_LOCKWINDOWUPDATE就好比你對窗口管理器說:“是我,讓我進去。”
             
            如果回頭看一下LockWindowUpdate函數的工作方式,你會發現如果一個鎖定的窗口沒有試圖做任何繪制,那么當窗口解鎖時,不會有區域被無效。盡管CS_SAVEBITS窗口類屬性會在窗口從屏幕上移除時自動保存原始的象素,并自動還原這些象素,LockWindowUpdate不會做任何類似的事。你需要自己負起責任確保在窗口被鎖定更新時你修改的象素,在調用LockWindowUpdate(NULL)后恢復到原始的值。這通常可以通過在做自己的繪圖操作前,將原始象素保存到一個屏幕外的位圖中,并在完成后將它們繪制回去。
             
            好,那么下面這就是意圖的使用方式:
             
            • 當你想接管另一個窗口的繪制,對那個窗口調用LockWindowUpdate。
            • 保存你將要覆蓋繪制的窗口的象素。
            • 繪制新的象素(這些象素往往是原始象素的修正,比如在將一個對象拖動到一個窗口上方時,你可能會添加一個表示此對象的圖片)。
            • 只要你的操作還在進行中,盡管重復。(這么做時,如果你正修改的屏幕區域與之前修改的不同,可能需要“備份”更多的屏幕上的象素。你可以增量的做備份/還原。例如,你不必在繪制新圖片前累計需要恢復的象素集,只需要先把保存的所有象素恢復到屏幕,然后計算拖動圖片的新位置,保存新位置處的象素,接著就可以在新位置繪制新圖片。通過這種方式,你只需要處理一組“備份象素”)
            • 當操作完成,恢復原始象素,并調用LockWindowUpdate(NULL)。

             

            下一篇,我們將看到“拖拽”這個詞的更多內容,以其是如何緊密的與整個LockWindowUpdate的概念綁定在一起的。
             
            盡管我們才剛剛開始討論LockWindowUpdate,你應當已經足以回管這個問題
             
            (注意:寫這個系列的目的在于描述LockWindowUpdate的意圖使用方式,不是討論這首先是不是一個好的設計)




            LockWindowUpdate系列3:什么樣的操作中應當使用LockWindowUpdate?

            如我在前面所說的,LockWindowUpdate的設計意圖可以用一個詞表達:拖拽。
            LockWindowUpdate最簡單的使用場景是在“拖動時顯示窗口內容”功能關閉的情況下,當你移動或是改變窗口尺寸時,被窗口管理器使用。當你開始移動/改變尺寸操作,窗口管理器鎖定整個桌面以便可以繪制細點矩形反饋,而不會因為其它窗口偶然與細點矩形交疊而導致沖突的風險。當移動/改變尺寸的操作完成,桌面被解鎖,所有東西恢復原貌。
             
            應用程序使用LockWindowUpdate的常見的場景,是希望為拖拽提供反饋而繪制一個自定義的圖片。在這個情況下,應用程序鎖定它自己的窗口以繪制拖拽的反饋。使用DCX_LOCKWINDOWUPDATE標志來獲取一個可以用來繪制所需的反饋的DC,這樣就不必擔心窗口函數或應用程序中任何其它的代碼偶然的繪制到反饋窗口上,并搞亂了拖拽圖片。例如,如果這個應用程序正在一個列表視圖中繪制拖拽的反饋,此時某個異步事件引發這個列表視圖的內容改變(比方說添加了一個列表項),并且拖拽的圖片正好在新添加的列表項要出現的位置,你一定不會想讓列表視圖的標準重繪行為覆蓋(或是更糟,重合)了拖拽的圖片。
             
            可能你需要鎖定其它應用程序的窗口的場景是當你要把一個物體拖過整個屏幕。如果你的程序是一個類似Spy那樣的程序,允許用戶通過拖拽一個“選擇器”到一個窗口上方來選擇它時,你可能會需要這么做。你需要鎖定用戶當前選擇的窗口,不僅讓它自己的重繪制不會與你的“選擇器”沖突,也使其不會與你放置在窗口邊沿的高亮效果沖突。
             
            現在,你可能已經注意到所有使用LockWindowUpdate場景中一個共同的思路:他們都和某種形式的拖拽有關。拖拽窗口的標題以移動它、拖拽窗口的邊框以改變它的尺寸、將一個對象拖入窗口或是拖出窗口。這不是一個巧合,LockWindowUpdate就是專門設計用于這些拖拽場景的。由于拖拽對象要用到鼠標按鍵,而只會有一個鼠標,故而同一時間不會有多個拖拽操作進行。因此,沒有必要同時鎖定多個窗口的更新。也許這個函數應當更準確的命名為LockDragWindow。




            LockWindowUpdate系列4:什么樣的操作中不應當使用LockWindowUpdate?

            那么,現在我們已經知道了什么樣的操作中應當使用LockWindowUpdate,現在我們來看一下人們在一些與拖拽無關的工作中錯誤使用這個函數的方式。
             
            人們看到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

            posted on 2010-11-04 22:39 楊粼波 閱讀(2688) 評論(0)  編輯 收藏 引用

            99热都是精品久久久久久| 久久久久亚洲AV成人网人人软件| 亚洲国产精品久久久久| 久久精品国产99久久丝袜| 久久综合给久久狠狠97色| 一本久久免费视频| 久久本道综合久久伊人| 国产成人精品久久综合| 久久天堂电影网| 91久久精品电影| 国产精品久久久久久久久久免费| 国产一级做a爰片久久毛片| 97久久精品人妻人人搡人人玩| 国产精品一区二区久久| 2021久久国自产拍精品| 国产成人精品白浆久久69| 久久99国产乱子伦精品免费| 看久久久久久a级毛片| www久久久天天com| 久久综合九色综合久99| 99久久伊人精品综合观看| 久久久久久亚洲精品无码| 伊人精品久久久久7777| 久久亚洲熟女cc98cm| 久久亚洲精品无码AV红樱桃| 久久精品无码一区二区无码| 91精品日韩人妻无码久久不卡| 97超级碰碰碰碰久久久久| 蜜臀久久99精品久久久久久| 久久精品无码一区二区WWW| 久久久精品国产sm调教网站 | 日日噜噜夜夜狠狠久久丁香五月 | 99久久国产综合精品成人影院 | 久久青青草原精品国产不卡| 国产69精品久久久久久人妻精品| avtt天堂网久久精品| 久久人人爽人人爽人人片AV麻豆 | 久久精品18| 久久中文骚妇内射| 欧美性大战久久久久久| 久久青青草原精品国产|