經(jīng)過一些對(duì)模態(tài)化的簡要介紹之后,今天我們來深入研究研究。
模態(tài)化的訣竅在于,當(dāng)調(diào)用一個(gè)模態(tài)函數(shù)時(shí),消息調(diào)度的責(zé)任由該函數(shù)處理,而不是由主程序處理。因此,如果你自定義了主程序的消息循環(huán),那么一旦你失去對(duì)模態(tài)循環(huán)的控制,這些自定義的部分就會(huì)丟失。
關(guān)于模態(tài)的另一個(gè)重要的事情是:WM_QUIT消息總是會(huì)打破模態(tài)循環(huán)。
在你自己的模態(tài)循環(huán)中一定要記住這一點(diǎn)! 如果你調(diào)用 PeekMessage 函數(shù)GetMessage 函數(shù)并取到了一條WM_QUIT消息,則不僅必須退出模態(tài)循環(huán),而且還必須重新生成 WM_QUIT消息(通過PostQuitMessage消息),這樣,下一個(gè)外層循環(huán)將看到 WM_QUIT 消息并進(jìn)行清理。 如果你未能傳播消息,下一個(gè)外層將不知道它需要退出,并且程序似乎會(huì)”卡在”其關(guān)閉代碼中,從而迫使用戶以艱難的方式終止進(jìn)程。
在后面的系列中,我們將看到這個(gè)圍繞WM_QUIT消息的約定是如何工作的。 但是現(xiàn)在,先牢記:模態(tài)循環(huán)應(yīng)該如何將WM_QUIT消息重新發(fā)布到下一個(gè)外層。
下面我們來看一個(gè)例子:
假設(shè)你的程序開始了一些操作,然后調(diào)用了WaitForSomething。在等待某事完成時(shí),程序的其他部分決定是時(shí)候退出了。 (也許用戶單擊了“退出”按鈕。)程序的其他部分將調(diào)用 PostQuitMessage(wParam) 來指示消息循環(huán)應(yīng)該終止。
投遞的WM_QUIT消息將首先由WaitForSomething函數(shù)中的GetMessage檢索。 如果檢索到的消息是 WM_QUIT 消息,GetMessage 函數(shù)將返回 FALSE。 在這種情況下,條件的“else”分支會(huì)被執(zhí)行,它會(huì)取消正在進(jìn)行的“Something”操作,然后將退出消息發(fā)送回消息隊(duì)列以供下一個(gè)外部消息循環(huán)處理。
當(dāng) WaitForSomething 返回時(shí),控制可能會(huì)退回到程序的主消息循環(huán)中。 然后主消息循環(huán)將檢索 WM_QUIT 消息并在最終退出程序之前進(jìn)行退出處理。
如果在 WaitForSomething 和程序的主消息循環(huán)之間有額外的模態(tài)層,每個(gè)層都會(huì)檢索 WM_QUIT 消息,進(jìn)行清理,然后在退出循環(huán)之前重新發(fā)布 WM_QUIT 消息(再次通過 PostQuitMessage)。
以這種方式,WM_QUIT 消息從一個(gè)模態(tài)循環(huán)傳遞到另一個(gè)模態(tài)循環(huán),直到它到達(dá)最外層的循環(huán),從而終止程序。
“但是等等,”我聽到你說。 “為什么我必須做所有這些花哨的 WM_QUIT 步法? 我可以只擁有一個(gè)名為 g_fQuitting 的私有小全局變量。 當(dāng)我想讓程序退出時(shí),我只是設(shè)置了這個(gè)變量,我所有的模態(tài)循環(huán)都會(huì)檢查這個(gè)變量,如果它被設(shè)置了就提前退出。 像這樣的東西:
所以我可以解決嵌套退出的問題,而無需執(zhí)行所有這些 PostQuitMessage 繁瑣的操作。”
你是對(duì)的,如果你控制了程序中的每一個(gè)模態(tài)循環(huán)。
但你沒有。
例如,當(dāng)你調(diào)用 DialogBox 函數(shù)時(shí),對(duì)話框代碼會(huì)運(yùn)行自己的私有模式循環(huán)來執(zhí)行對(duì)話框 UI,直到你開始調(diào)用 EndDialog 函數(shù)。 并且每當(dāng)用戶單擊你的任何菜單時(shí),Windows 都會(huì)運(yùn)行自己的私有模式循環(huán)來執(zhí)行菜單 UI。 事實(shí)上,即使是應(yīng)用程序窗口的大小調(diào)整也是由 Windows 模態(tài)循環(huán)處理的。
當(dāng)然,Windows 不知道你的小 g_fQuitting 變量,因此它不知道你要退出。 正是 WM_QUIT消息來負(fù)責(zé)系統(tǒng)的不同部分之間退出的協(xié)調(diào)工作。
請(qǐng)注意,這個(gè)關(guān)于 WM_QUIT 消息的約定是雙向的。 你可以使用這個(gè)約定來退出模態(tài)循環(huán)(我們稍后會(huì)看到更多),但它也要求你遵守這個(gè)約定,以便其他組件(包括窗口管理器本身)可以讓你的模態(tài)循環(huán)退出。
總結(jié)
試著增加這些Windows消息循環(huán)的底層知識(shí),有助于你比其他程序員”更懂”。
其他人教你做事的機(jī)會(huì),也相對(duì)少。
最后
Raymond Chen的《The Old New Thing》是我非常喜歡的博客之一,里面有很多關(guān)于Windows的小知識(shí),對(duì)于廣大Windows平臺(tái)開發(fā)者來說,確實(shí)十分有幫助。
本文來自:《Modality, part 3: The WM_QUIT message》
責(zé)任編輯:Rex_08