一、WM_CLOSE、WM_DESTROY、WM_QUIT區別
WM_CLOSE:關閉應用程式視窗
WM_DESTROY:關閉應用程式WM_QUIT:關閉訊息迴圈只有關閉了訊息迴圈,應用程式的進程才真正退出(在工作管理員裡消失)。win32應用程式的完整退出過程:點擊視窗右上方的關閉按鈕,發送WM_CLOSE訊息。此訊息處理中調用DestroyWindow函數,發送WM_DESTROY訊息。此訊息處理中調用PostQuitMessage(0)函數,發送WM_QUIT訊息到訊息佇列中。GetMessage捕獲到WM_QUIT,返回0,退出迴圈(應用程式真正退出)。tips:按照上述正常流程,WM_QUIT是不會到達視窗過程的。(因為在GetMessage截獲了WM_QUIT訊息之後,程式已經徹底退出了!)MFC應用程式的完整退出過程:點擊視窗右上方的關閉按鈕,或選擇【File/Close】,發出 WM_CLOSE訊息。CMyFrameWnd 並沒有設定WM_CLOSE
處理常式,於是交給預設之處理常式。預設函數對於WM_CLOSE 的處理方式是呼叫 ::DestroyWindow, 並因而發出WM_DESTROY。預設之WM_DESTROY 處理方式是呼叫::PostQuitMessage,因此發出WM_QUIT。CWinApp::Run 收到WM_QUIT 後會結束其內部之訊息迴路, 然後呼叫ExitInstance,這是CWinApp 的?個虛擬函數。如果自己應用程式累CMyWinApp 改寫了ExitInstance , 那麼CWinApp::Run 所呼叫的就是CMyWinApp::ExitInstance,否則就是
CWinApp::ExitInstance。最後回到 AfxWinMain,執行 AfxWinTerm,結束程式。附加:當調用DestroyWindow函數後,作業系統就會進行一系列的刪除動作,先發送WM_DESTROY訊息,接著發送WM_NCDESTROY訊息。如果這個視窗還有子視窗或者是其它視窗的所有者,就需要給所有子視窗發送刪除訊息。WM_QUIT是唯一可以使GetMessage(&msg,NULL,0,0)返回假值的訊息.相關程式碼分析://主函數中進入訊息迴圈的代碼片斷
while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg); //將訊息進行處理一下
DispatchMessage(&msg); //再將訊息變數msg傳給windows,讓windows來調用訊息處理函數
}如果把GetMessage(&msg,NULL,0,0)改為GetMessage(&msg,hWnd,0,0),則發現關閉應用程式後,工作管理員中仍有該程式的進程,且佔用大量的記憶體,why?msdn中的原因解釋;對於GetMessage(&msg,hWnd,0,0),當第二個參數無效時,此函數傳回值為-1。對於上述迴圈來說,此while條件為真,因此進入死迴圈,進程無法退出。
二、各種訊息投遞函數
1、SendMessage:發送訊息給指定的視窗過程;直到視窗過程處理了訊息才返回。
2、PostMessage:將訊息放入訊息佇列(與指定視窗建立的線程相關)中;無需等待訊息處理,立即返回。 不能發送WM_QUIT訊息,此訊息只能由PostQuitMessage函數發送。
3、PostThreadMessage:發送訊息給指定線程的訊息佇列;無需等待線程處理訊息,立即返回。 此函數發送的訊息和視窗是無關的。我們只需指定線程ID就OK了,但要保證線程已建立,否則會失敗。
4、GetMessage:從調用線程的訊息佇列中取訊息。 當第二個參數為NULL時,它檢索以下兩種訊息: a、屬於調用線程的任何視窗的訊息; b、由PostThreadMessag投遞給該調用線程的訊息。
5、PeekMessage:功能同GetMessage。區別是: GetMessage:直到一個匹配了過濾條件的訊息,被放到訊息佇列中才返回。 PeekMessage:不管訊息是否放入隊列,立即返回。
6、DispatchMessage:派遣訊息給相應的視窗過程。
7、TranslateMessage:轉換虛擬鍵資訊到字元訊息。