windows消息之PostMessage和SendMessage的內部實現
原文:http://blog.csdn.net/sunyikuyu/article/details/8811400
PostMessage和SendMessage是常用的發送消息函數。那兩者有什麼區別呢?
大家都知道PostMessage是向一個窗口Post一個消息,並且不再關注該消息是否被處理。
SendMessage是向窗口發送完消息後,會一直等着該窗口把消息處理完成。
那下面的問題你能回答麼
1. PostMessage向自身線程窗口發消息與向非自身線程窗口發消息實現方法一樣麼?
2. SendMessage向自身線程窗口發消息與向非自身線程窗口發消息實現方法一樣麼?
3. SendMessage的窗口非自身進程,需要做額外的操作麼?
4. SendMessage怎麼實現消息的同步?
如果你知道上面的答案,那請關閉該頁面。
以下內容參考了ReactOS 0.3.14源碼,並從中整理而來。
PostMessage函數大致分爲以下步驟:
1. 如果Wnd爲Null,則是一個當前線程消息(與窗口無關),調用UserPostThreadMessage函數處理
1.1. Copy 消息結構到內核(消息結構的Wnd成員爲Null)
1.2. 把該消息結構掛接到Wnd對應的線程消息隊列中的Post消息鏈表中
1.3. 置線程消息隊列的消息事件爲有信號狀態,通知它有新消息來了
2. 如果Wnd爲0xFFFF,則該消息是一個廣播,則向該桌面所有頂層窗口發送該消息。使用UserPostMessage函數
3. Wnd不爲Null也不爲0xFFFF,則該窗口爲一個有效窗口,這時候會檢查Msg是否等於WM_QUIT
3.1. 如果Msg等於WM_QUIT
3.1.1. 置消息隊列的QuitPosted字段爲True
3.1.2. 置退出碼到QuitExitCode字段
3.1.3. 置線程消息隊列的消息事件爲有信號狀態,通知它有新消息來了
3.2. 如果Msg不等於WM_QUIT
3.2.1. Copy 消息結構到內核(這樣可以進程間共享)
3.2.2. 把該消息結構掛接到Wnd對應的線程消息隊列中的Post消息鏈表中
3.2.3. 置線程消息隊列的消息事件爲有信號狀態,通知它有新消息來了
SendMessage函數大致分爲以下步驟:
1. 複製一份消息結構到內核中,以後就使用內核這份消息結構
2. 如果Wnd屬於自身線程,則直接調用窗口自身的消息處理函數處理該消息
3. 如果WND不屬於自身線程窗口
3.1. 構建一個消息結構,並且初始化一個Event事件,如果該消息被處理,該事件就會變成有信號狀態
3.2. 把該消息結構掛接到Wnd對應的線程消息隊列中的Send消息鏈表中
3.3. 置線程消息隊列的消息事件爲有信號狀態,通知它有新消息來了
3.4. 調用KeWaitForSingleObject無限等待Event事件。直到變成有信號狀態
3.5. 如果消息被處理,則返回
有上面的說明可知,PostMessage比SendMessage簡潔的多。
另外SendMessage有好幾個變種,如SendMessageCallback、SendMessageTimeout等。
SendMessageCallback是吧消息放入Send消息鏈表中後,不會等待消息被執行,而是直接返回。當該消息被執行時,CallBack函數就會被調用
SendMessageTimeout是KeWaitForSingleObject有限等待。如果超時未處理則返回,並把該消息從Send消息列表中摘除。
最後,回答一下上面提到的問題:
1. PostMessage向自身線程窗口發消息與向非自身線程窗口發消息實現方法一樣麼?
一樣
2. SendMessage向自身線程窗口發消息與向非自身線程窗口發消息實現方法一樣麼?
不一樣
3. SendMessage的窗口非自身進程,需要做額外的操作麼?
消息與進程無關
4. SendMessage怎麼實現消息的同步?
通過KeWaitForSingleObject等待Event事件。該消息被處理時Event就會被置成有信號狀態