PeekMessage/GetMessage SendMessage和PostMessage SendMessageTimeOut

1.PeekMessage/GetMessage

  兩個函數主要有以下兩個區別:
    1.GetMessage只有在等到消息時才返回,沒有消息時就會阻塞線程,這時線程的時間片將會被出讓給別的線程。而且當GetMessage遇到WM_QUIT時,將會返回0.
      而PeekMessage只是檢查一下消息隊列,有沒有消息都會立即返回,只是在沒有消息的時候返回值爲0. 所以PeekMessage無論有無消息都不會出讓線程的時間片。
    2.GetMessage會將消息從隊列中刪除,而PeekMessage可以設置最後一個參數wRemoveMsg來決定是否將消息保留在隊列中。
   
    BOOL GetMessage(
      LPMSG lpMsg,              // 一個MSG的指針
      HWND hWnd,               // 一般爲當前窗口的句柄
      UINT wMsgFilterMin,   // 指定被檢索的最小消息值的整數
      UINT wMsgFilterMax   // 指定被檢索的最大消息值的整數
    );
    如果第三,四個參數都爲零,則取所有的消息。
    如果出現錯誤,比如參數一或參數而指向的指針或句柄無效,則會返回-1.
   
    BOOL PeekMessage(
      LPMSG lpMsg,                 // 一個MSG的指針
      HWND hWnd,                  //
      UINT wMsgFilterMin,      //
      UINT wMsgFilterMax,     // 前四個參數和GetMessage的一樣
      UINT wRemoveMsg       // 取完消息要做的操作
    );
    wRemoveMsg:確定消息如何被處理。此參數可取下列值之一:
    PM_NOREMOVE:PeekMessage處理後,消息不從隊列裏除掉。
    PM_REMOVE:PeekMessage處理後,消息從隊列裏除掉,一般都是採用這種刪除的方法。

    GetMessage舉例
    // 主消息循環:
     while (GetMessage(&msg, NULL, 0, 0))
     {
      if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
      {
       TranslateMessage(&msg);
       DispatchMessage(&msg);
      }
     }
     
    PeekMessage舉例:
    while(1)
    {
        if(PeekMessage(&msg, NULL, 0, 0))
        {
          TranslateMessage(&msg);
       DispatchMessage(&msg);
        }
        else
        {
            //do other things
        }
   
    }
   
   
2.SendMessage和PostMessage

    下面以線程A向線程B發送消息爲例來說明:

    (1).如果線程A和線程B是同一線程:
    PostMessage會將消息壓入窗口所在線程的消息隊列,然後立即返回,返回值標誌消息放到線程隊列是否成功;然後這個消息會通過消息循環Dispatch到目標窗口。
    而SendMessage則不經過消息隊列,SendMessage可認爲是直接調用了該窗口的窗口過程,在窗口過程執行完畢之後SendMessage纔會返回。SendMessage的返回值就是窗口過程的返回值。

    (2).如果線程A和線程B是不同的線程:
    在多線程應用中,PostMessage的用法還是一樣,但是最好用PostThreadMessage代替PostMessage,他工作的很好。
    然而SendMessage則不同了。如果在線程A中向線程B所創建的一個窗口hWndB發送消息SendMessage(hWndB,WM_MSG,0,0),那麼系統將會立即將執行權從線程A切換到線程B,然後在線程B中調用hWndB的窗口過程來處理消息,並且在處理完該消息後,執行權仍然在B手中!這個時候,線程A則暫停在SendMessage處,等待下次線程A獲得執行權後才繼續執行,並且仍然可以獲得消息處理的結果(返回值)。一般,爲了避免死鎖,在B中對WM_MSG做出處理之前,要加上:
   
      if(InSendMessage())
        RelpyMessage(lResult);
    即判斷:如果該消息是發自另外一個線程,則立即 RelpyMessage,回覆消息,參數lResult即是返回值。而如果是在同一個線程內,則InSendMessage()將會返回FALSE。
   
3.SendMessageTimeOut
作用是:設定等待消息返回的最大時間。

當線程A通過SendMessage向線程B發送消息,但是在SendMessage沒有返回的時候,線程A可能會收到非隊列消息(nonqueued messages,比如其他線程用SendMessage向線程A發送消息)。
由於一個線程在等待發送的消息返回時允許被中斷,以便處理另一個發送來的消息。也就是說這時調用線程A對應的窗口過程是允許的。我們可以使用SendMessageTimeOut函數的SMTO_BLOCK阻止這樣的中斷。
但是這樣可能引起死鎖,比如這時線程B又向線程A發送一個非隊列消息。這種情況下兩個線程都得不到執行,將永遠掛起。

 


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章