• <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>

            牽著老婆滿街逛

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





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

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

             

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




            LockWindowUpdate系列3:什么樣的操作中應(yīng)當(dāng)使用LockWindowUpdate?

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




            LockWindowUpdate系列4:什么樣的操作中不應(yīng)當(dāng)使用LockWindowUpdate?

            那么,現(xiàn)在我們已經(jīng)知道了什么樣的操作中應(yīng)當(dāng)使用LockWindowUpdate,現(xiàn)在我們來看一下人們在一些與拖拽無關(guān)的工作中錯誤使用這個函數(shù)的方式。
             
            人們看到LockWindowUpdate“鎖定的窗口將不能繪制自己”的行為,就用它來作為WM_SETREDRAW消息的偷懶的使用方式,盡管發(fā)送一個WM_SETREDRAW消息不不比調(diào)用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)
             
            就像我們在前面所說的,同一時間系統(tǒng)中只能有一個窗口的更新被鎖定。如果你調(diào)用LockWindowUpdate的目的僅僅是防止窗口重繪,比如因為你在更新這個窗口,在你的更新完成前,不希望它不停的刷新,那么請直接禁止窗口的重繪。如果你使用了LockWindowUpdate,將引來無數(shù)下面的問題。
             
            首先,如果另一個什么程序也以同樣錯誤的方式使用LockWindowUpdate,那么你們中會有一個人失敗。首先調(diào)用LockWindowUpdate的程序?qū)晒Γ诙€調(diào)用的程序?qū) ,F(xiàn)在你準(zhǔn)備怎么辦?你的窗口不會被鎖定。
             
            其次,如果你鎖定了自己的窗口更新,這時用戶切換到另一個程序,并試圖拖拽一個對象(或甚至只是嘗試移動一下那個窗口),那一個LockWindowUpdate將會失敗,于是用戶遇到了一個由于某種神秘原因拖放失效的情形。然后,10秒鐘后,一切功能又運作作正常。“愚蠢的爛Windows”用戶嘀咕道。
             
            反過來說,如果你在一個拖放或是窗口移動的過程中準(zhǔn)備調(diào)用LockWindowUpdate,那么你的調(diào)用就會失敗。
             
            這只是更一般意義上,使用全局狀態(tài)來處理局部情況的編程錯誤中,比較具體的例子。當(dāng)你想禁止自己的一個窗口的重繪時,你不會希望這會影響到系統(tǒng)中的其它窗口。更新自己的窗口是一個局部情況,但是你使用了全局狀態(tài)(被鎖定更新的窗口)來維持它。
             
            我可以預(yù)料到有人會說:“那么,窗口管理器應(yīng)當(dāng)阻止人們在一個非拖放操作中鎖定窗口更新。”問題是,窗口管理器怎么知道這個?它只是知道發(fā)生了什么事情,但不知道為什么發(fā)生。一個程序到底是由于懶于使用WM_SETREDRAW消息而使用LockWindowUpdate?還是為了響應(yīng)引發(fā)拖放操作的用戶輸入?這里沒辦法說“用戶鼠標(biāo)按鍵壓下了”,因為用戶可能用基于鍵盤的理論上和拖放等價的操作(例如使用方向鍵來改變窗口尺寸)。基本上這個問題很難于解決,除非計算機(jī)能更多一點對讓他做的事情的猜想。
             
            下一回是對LockWindowUpdate的最終評論。




            LockWindowUpdate系列5:關(guān)于LockWindowUpdate的最終評論 

            現(xiàn)在大家了解了LockWindowUpdate的設(shè)計意圖,我現(xiàn)在將要告訴大家你們?yōu)槭裁床粦?yīng)當(dāng)使用這個函數(shù),甚至不是因為其設(shè)計意圖的緣因。
             
            這需要回到LockWindowUpdate被創(chuàng)造出來的歷史環(huán)境。回到16位Windows(特別是Windows 3.1)的時代。在那時,內(nèi)存還是很昂貴的,顯示驅(qū)動功能也很有限。還沒有DirectX,沒有AlphaBlend函數(shù)。你所擁有的一切就是一塊屏幕緩沖區(qū)。LockWindowUpdate函數(shù)允許你接管這個屏幕緩沖區(qū)中對應(yīng)一個窗口的部分,以得以在不需窗口知道的情況下應(yīng)用自己特別的效果。
             
            Windows 3.1距今已經(jīng)十年多了,在這期間,我們有了DirectX覆蓋、區(qū)域化窗口、分層窗口、alpha混合、桌面合成,種種我們在過去不曾擁有的絕妙圖象特效。特別是這些美妙的分層窗口和區(qū)域化窗口,允許你做幾乎所有你希望用LockWindowUpdate去做的事情。如果你希望在一個窗口邊沿繪制高亮,你可以在其邊沿放置一個區(qū)域化窗口。如果你希望在一個窗口上方繪制一個拖拽圖片,你只需要創(chuàng)建一個分層窗口,并把它放置到目標(biāo)窗口上方即可。使用的是分層窗口、一個區(qū)域及你想要的無論哪一種奇特的alpha通道,而將冗重的alpha混合和合成推給圖象引擎來完成。更好的是,分層窗口可以伸展到拖拽經(jīng)過的窗口以外,這是LockWindowUpdate無法完成的。(你可以在Windwos XP中看到這種特效,在資源管理器窗口中“全選”,并將整個選擇內(nèi)容在屏幕上拖拽。你將看到拖拽圖像沒有局限于拖拽經(jīng)過的窗口邊界。)
              
            更甚者,在Vista的桌面窗口管理器(desktop window manager)令人驚奇的全新合成方式中,LockWindowUpdate更是不再值得使用。鎖定一個特定窗口的更新還不算太成問題,因為桌面窗口管理器可以只是給你這個窗口的后臺位圖。但是如果你鎖定了整個屏幕(我常見到人們這么做),桌面窗口管理器就需要將所有窗口合成到一個實際位圖中,以便在你使用DCX_LOCKWINDOWUPDATE標(biāo)志調(diào)用GetDCEx時可以返回給你。桌面窗口管理器通常是在DirectX和顯示驅(qū)動加速的輔助下直接進(jìn)行合成的,所有的合成結(jié)果通常是直接送到屏幕上,實際上根本不會存放在一個“合成后的”位圖中。但是如果你鎖定了屏幕,并請求一個屏幕的DC,桌面窗口管理器只得模擬老式的行為,使得你可以訪問一個代表了假如根本沒有合成這回事的情況下,你“應(yīng)當(dāng)?shù)玫?/em>”的東西。這并不輕松
             
            尾聲。我并不清楚這個系列是否成功。我的目標(biāo)只是幫助人們更有效的使用LockWindowUpdate,并在LockWindowUpdate不適于一個工作時指導(dǎo)他們轉(zhuǎn)向其它的替代物。換句話說,這是一篇關(guān)于LockWindowUpdate的文章,不是函數(shù)文檔。我試圖讓我的表達(dá)顯得輕松一些,但我估計我的幽默并不好笑,人們只是用他們來做為否定注解的跳板。
             
            特別感謝那些把這個系列用來作為一個抱怨文檔的機(jī)會的人們。我的意思是,咄,如果文檔是完美的,我也大可不必寫這么一個系列。不過這些人們往往只是看了函數(shù)說明那一頁,而忽視了閱讀所有文檔。嘿,除了單純的函數(shù)說明外,還有更多的文檔哪!函數(shù)說明只是一個參考,你應(yīng)當(dāng)是在已經(jīng)知道會發(fā)生什么,并只是需要微調(diào)一些細(xì)節(jié)時,才會到那里去看一下。真正的學(xué)習(xí)應(yīng)當(dāng)是從概覽和文章中去進(jìn)行。如果你想學(xué)習(xí)如何操作你的收音機(jī),你不會上來就看電路圖的。
             
            我認(rèn)為當(dāng)Ronald D. Moore說“聽播客時你必須有足夠的忍耐力”時,他一定是在搞什么鬼。



            LockWindowUpdate系列1:LockWindowUpdate的行為?

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

            LockWindowUpdate系列3:什么樣的操作中應(yīng)當(dāng)使用LockWindowUpdate?

            LockWindowUpdate系列4:什么樣的操作中不應(yīng)當(dāng)使用LockWindowUpdate?

            LockWindowUpdate系列5:關(guān)于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 楊粼波 閱讀(2698) 評論(0)  編輯 收藏 引用


            只有注冊用戶登錄后才能發(fā)表評論。
            網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


            国产福利电影一区二区三区,免费久久久久久久精| 久久本道综合久久伊人| 狠狠色婷婷久久一区二区| 久久亚洲中文字幕精品一区| 久久久久亚洲AV无码专区体验| 久久国产乱子伦精品免费强| 久久久久久国产a免费观看不卡| 中文字幕无码久久精品青草 | 国产精品禁18久久久夂久| 国产精品九九九久久九九| 亚洲国产成人精品无码久久久久久综合| 伊人久久大香线蕉AV一区二区| 2021久久国自产拍精品| 伊人色综合九久久天天蜜桃| 99久久久久| 国内精品久久人妻互换| 婷婷久久综合九色综合绿巨人| 18岁日韩内射颜射午夜久久成人| 国内精品伊人久久久久妇| 国产高潮久久免费观看| 69久久夜色精品国产69| 久久香蕉超碰97国产精品| 香蕉99久久国产综合精品宅男自 | 久久国产精品一区| AV无码久久久久不卡蜜桃| 久久亚洲精品无码VA大香大香| 岛国搬运www久久| 久久午夜电影网| 99久久精品国产高清一区二区| 99精品久久精品一区二区| 波多野结衣久久一区二区| 久久天天躁狠狠躁夜夜不卡 | 青青草原综合久久大伊人| 久久露脸国产精品| 欧美精品福利视频一区二区三区久久久精品 | 久久国产免费直播| 狠狠人妻久久久久久综合| 国产精品成人99久久久久 | av午夜福利一片免费看久久| 国产∨亚洲V天堂无码久久久| 久久综合综合久久综合|