1. 程式人生 > >PostMessage(非同步)和SendMessage(同步)的區別

PostMessage(非同步)和SendMessage(同步)的區別

PostMessage和SendMessage的區別

1, PostMessage只把訊息放入佇列,不管其他程式是否處理都返回,然後繼續執行,這是個非同步訊息投放函式。而SendMessage必須等待其他程式處理訊息完了之後才返回,繼續執行,這是個同步訊息投放函式。而且,PostMessage的返回值表示PostMessage函式執行是否正確;而SendMessage的返回值表示其他程式處理訊息後的返回值。這點大家應該都明白。

2, 如果在同一個執行緒內,PostMessage傳送訊息時,訊息要先放入執行緒的訊息佇列,然後通過訊息迴圈Dispatch到目標視窗。SendMessage傳送訊息時,系統直接呼叫目標視窗的訊息處理程式,並將結果返回。SendMessage在同一執行緒中傳送訊息並不入執行緒訊息佇列。 如果在不同執行緒內。最好用PostThreadMessage代替PostMessage,他工作的很好。SendMessage傳送訊息到目標視窗所屬的執行緒的訊息佇列,然後傳送訊息的執行緒等待(事實上,他應該還在做一些監測工作,比如監視QS_SENDMESSAGE標誌),直到目標視窗處理完並且結果返回,傳送訊息的執行緒才繼續執行。這是SendMessage的一般情況,事實上,處理過程要複雜的多。比如,當傳送訊息的執行緒監測到有別的視窗SendMessage一個訊息到來時,他直接呼叫視窗處理過程(重入),並將處理結果返回(這個過程不需要訊息迴圈中GetMessage等的支援)。

3, msdn: If you send a message in the range below WM_USER to the asynchronous message functions (PostMessage, SendNotifyMessage, and SendMessageCallback), its message parameters can not include pointers. Otherwise, the operation will fail.

如果傳送的訊息碼在WM_USER之下(非自定義訊息)且訊息引數中帶有指標,那麼PostMessage,SendNotifyMessage,SendMessageCallback這些非同步訊息傳送函式將會呼叫失敗。 最好不要用PostMessage傳送帶有指標引數的訊息。

在除錯程式的時候發現,用PostMessage 傳出去的值在我使用的時候已經發生了變化,百思不得其解。

用迴圈去找一個檔案,找到的檔名稱暫存在一個臨時變數裡面,找到之後把這個名稱傳到另外的函式處理,除錯發現,處理的總是在我需要的檔案後面找到的檔案,原因是在我使用的時候那個暫存變數裡面的值已經發生了變化(迴圈已經處理到了下一步了),

PostMessage 和SendMessage的區別主要在於是否等待其他程式訊息處理。PostMessage只是把訊息放入佇列,不管其他程式是否處理都返回,然後繼續執行;而SendMessage必須等待其他程式處理訊息後才返回,繼續執行。這兩個函式的返回值也不同,PostMessage的返回值表示PostMessage函式執行是否正確,而SendMessage的返回值表示其他程式處理訊息後的返回值。

使用SendMessage()可以解決這個問題,只不過在時間效率上會有點下降。

函式原型:

    LRESULT SendMessage(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam);

    BOOL       PostMessage(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam);

LRESULT 返回訊息被處理的結果,在訊息被處理之後才會返回。BOOL 只是返回傳送的結果,是不是已經送到訊息佇列。

從網路上找到一些資料:

1       PostMessage 是非同步的,SendMessage 是同步的。

          PostMessage 只把訊息放到佇列,不管訊息是不是被處理就返回,訊息可能不被處理;

          SendMessage等待訊息被處理完了才返回,如果訊息不被處理,傳送訊息的執行緒將一直處於阻塞狀態,等待訊息的返回。

2          同一個執行緒內:

             SendMessage 傳送訊息時,由USER32.DLL模組呼叫目標視窗的訊息處理程式,並將結果返回,SendMessage 在同一個執行緒裡面傳送訊息不進入執行緒訊息佇列;PostMessage 傳送的訊息要先放到訊息佇列,然後通過訊息迴圈分派到目標視窗(DispatchMessage)。

3          不同執行緒:

             SendMessage 傳送訊息到目標視窗的訊息佇列,然後傳送訊息的執行緒在USER32。DLL模組內監視和等待訊息的處理結果,直到目標視窗的才處理返回,SendMessage在返回之前還需要做許多工作,如響應別的執行緒向它傳送的SendMessage().PostMessge() 到別的執行緒的時候最好使用PostThreadMessage   代替。PostMessage()的HWND 引數可以為NULL,相當於PostThreadMessage() + GetCrrentThreadId.

4          系統處理訊息。

             系統只處理(marshal)系統訊息(0--WM_USER),傳送使用者訊息(使用者自己定義)時需要使用者自己處理。

             使用PostMessage,SendNotifyMessage,SendMessageCallback等非同步函式傳送系統訊息時,引數不可以使用指標,因為傳送者不等待訊息的處理就返回,接收者還沒有處理,指標就有可能被釋放了,或則內容變化了。

5 在Windows 2000/XP,每個訊息佇列最多隻能存放一定數量的訊息,超過的將不會被處理就丟掉。系統預設是10000;:[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows] USERPostMessageLimit

可以修改(我的系統下沒有發現)。

在控制別的應用程式的時候,經常需要等待直到某個功能結束,例如:

    開啟一個視窗-->等待直到視窗結束 ,這個時候就可以用到SendMessage

    如果在開啟這個視窗後仍然需要對該視窗的介面進行設定,比如Edit的value等等,比如:

       開啟一個視窗-->控制視窗的control的屬性

    這個時候就需要PostMessage

使用一個鉤子程式截獲訊息後,使用SendMessage把訊息傳送到主處理程式進行處理,但是在主處理程式還沒有完成任務的時候,被設定鉤子的程式進入了停止的狀態,不可以處理 WM_PAINT, WM_MOVE, .......等的基本資訊, 必須要等SendMessage傳送出的訊息完成後,才能繼續執行,整個介面一片空白,把鉤子訊息設定成PostMessage的傳送訊息形式後,問題解決!

       PostMessage只是把訊息放入佇列,不管其他程式是否處理都返回,然後繼續執行;

    而SendMessage必須等待其他程式處理訊息後才返回,繼續執行。

       PostMessage的返回值表示PostMessage函式執行是否正確;

    而SendMessage的返回值表示其他程式處理訊息後的返回值。

    使用這兩個傳送訊息函式的最重要的是要看你的程式是否要對訊息的滯後性關注否,PostMessage會造成訊息的滯後性,而SendMessage則不會,

訊息中儘量要傳值,避免傳遞指標

-------------------------------------------------------------------------------------------------------------------

SendMessage函式功能:該函式將指定的訊息傳送到一個或多個視窗。此函式為指定的視窗呼叫視窗程式,直到視窗程式處理完訊息再返回,是同步訊息投放函式。而函式PostMessage不同,將一個訊息寄送到一個執行緒的訊息佇列後立即返回,是非同步訊息投放函式。
函式原型:LRESULT SendMessage(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM IParam);
引數
  hWnd:其視窗程式將接收訊息的視窗的控制代碼。如果此引數為HWND_BROADCAST,則訊息將被髮送到系統中所有頂層視窗,包括無效或不可見的非自身擁有的視窗、被覆蓋的視窗和彈出式視窗,但訊息不被髮送到子視窗。
  Msg:指定被髮送的訊息。
  wParam:指定附加的訊息指定資訊。
  IParam:指定附加的訊息指定資訊。
返回值:返回值指定訊息處理的結果,依賴於所傳送的訊息。
備註:需要用HWND_BROADCAST通訊的應用程式應當使用函式RegisterWindowMessage來為應用程式間的通訊取得一個唯一的訊息。
  如果指定的視窗是由呼叫執行緒建立的,則視窗程式立即作為子程式呼叫。如果指定的視窗是由不同執行緒建立的,則系統切換到該執行緒並呼叫恰當的視窗程式。執行緒間的訊息只有在執行緒執行訊息檢索程式碼時才被處理。傳送執行緒被阻塞直到接收執行緒處理完訊息為止。
PostMessage函式功能:該函式將一個訊息放入(寄送)到與指定視窗建立的執行緒相聯絡訊息佇列裡,不等待執行緒處理訊息就返回。訊息佇列裡的訊息通過呼叫GetMessage和PeekMessage取得。
函式原型:B00L PostMessage(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam);
引數
  hWnd:其視窗程式接收訊息的視窗的控制代碼。可取有特定含義的兩個值:
  HWND.BROADCAST:訊息被寄送到系統的所有頂層視窗,包括無效或不可見的非自身擁有的視窗、被覆蓋的視窗和彈出式視窗。訊息不被寄送到子視窗。
  NULL:此函式的操作和呼叫引數dwThread設定為當前執行緒的識別符號PostThreadMessage函式一樣。
  Msg:指定被寄送的訊息。
  wParam:指定附加的訊息特定的資訊。
  IParam:指定附加的訊息特定的資訊。
返回值:如果函式呼叫成功,返回非零值:如果函式呼叫失敗,返回值是零。若想獲得更多的錯誤資訊,請呼叫GetLastError函式。
備註:需要以 HWND_BROADCAST方式通訊的應用程式應當用函式 RegisterwindwosMessage來獲得應用程式間通訊的獨特的訊息。
  如果傳送一個低於WM_USER範圍的訊息給非同步訊息函式(PostMessage.SendNotifyMessage,SendMesssgeCallback),訊息引數不能包含指標。否則,操作將會失敗。函式將再接收執行緒處理訊息之前返回,傳送者將在記憶體被使用之前釋放。

速查:Windows NT: 3.1及以上版本; Windows:95及以上版本;Windows CE:1.0及以上版本;標頭檔案:winuser.h;輸入庫:user32.lib;Unicode:在Windows NT環境下以Unicode和ANSI方式實現。

備註的備註:

如果在同一個執行緒內,PostMessage傳送訊息時,訊息要先放入執行緒的訊息佇列,然後通過訊息迴圈Dispatch到目標視窗。SendMessage傳送訊息時,系統直接呼叫目標視窗的訊息處理程式,並將結果返回。SendMessage在同一執行緒中傳送訊息並不入執行緒訊息佇列。 如果在不同執行緒內,最好用PostThreadMessage代替PostMessage,他工作的很好。SendMessage傳送訊息到目標視窗所屬的執行緒的訊息佇列,然後傳送訊息的執行緒等待(事實上,他應該還在做一些監測工作,比如監視QS_SENDMESSAGE標誌),直到目標視窗處理完並且結果返回,傳送訊息的執行緒才繼續執行。這是SendMessage的一般情況,事實上,處理過程要複雜的多。比如,當傳送訊息的執行緒監測到有別的視窗SendMessage一個訊息到來時,他直接呼叫視窗處理過程(重入),並將處理結果返回(這個過程不需要訊息迴圈中GetMessage等的支援)。