SendMessage、PostMessage原理(1)

本文講解SendMessage、PostMessage兩個函數的實現原理,分爲三個步驟進行講解,分別適合初級、中級、高級程序員進行理解,三個步驟分別爲:

1、SendMessage、PostMessage的運行機制。

2、SendMessage、PostMessage的運行內幕。

3、SendMessage、PostMessage的內部實現。

注:理解這篇文章之前,必須先了解Windows的消息循環機制。

 

1、SendMessage、PostMessage的運行機制

我們先來看最簡單的。

SendMessage可以理解爲,SendMessage函數發送消息,等待消息處理完成後,SendMessage才返回。稍微深入一點,是等待窗口處理函數返回後,SendMessage就返回了。

PostMessage可以理解爲,PostMessage函數發送消息,不等待消息處理完成,立刻返回。稍微深入一點,PostMessage只管發送消息,消息有沒有被送到則並不關心,只要發送了消息,便立刻返回。

對於寫一般Windows程序的程序員來說,能夠這樣理解也就足夠了。但SendMessage、PostMessage真的是一個發送消息等待、一個發送消息不等待嗎?具體細節,下面第2點將會講到。

 

2、SendMessage、PostMessage的運行內幕

在寫一般Windows程序時,如上第1點講到的足以應付,其實我們可以看看MSDN來確定SendMessage、PostMessage的運行內幕。

在MSDN中,SendMessage解釋如爲:The SendMessage function sends the specified message to a window or windows. It calls the window procedure for the specified window and does not return until the window procedure has processed the message.

翻譯成中文爲:SendMessage函數將指定的消息發到窗口。它調用特定窗口的窗口處理函數,並且不會立即返回,直到窗口處理函數處理了這個消息。

再看看PostMessage的解釋:The PostMessage function places (posts) a message in the message queue associated with the thread that created the specified window and returns without waiting for the thread to process the message.

    翻譯成中文爲:PostMessage函數將一個消息放入與創建這個窗口的消息隊列相關的線程中,並立刻返回不等待線程處理消息。

仔細看完MSDN解釋,我們瞭解到,SendMessage的確是發送消息,然後等待處理完成返回,但發送消息的方法爲直接調用消息處理函數(即WndProc函數),按照函數調用規則,肯定會等消息處理函數返回之後,SendMessage才返回。而PostMessage卻沒有發送消息,PostMessage是將消息放入消息隊列中,然後立刻返回,至於消息何時被處理,PostMessage完全不知道,此時只有消息循環知道被PostMessage的消息何時被處理了。

至此我們撥開了一層疑雲,原來SendMessage只是調用我們的消息處理函數,PostMessage只是將消息放到消息隊列中。下一節將會更深入這兩個函數,看看Microsoft究竟是如何實現這兩個函數的。

 

3、SendMessage、PostMessage的內部實現

Windows內部運行原理、機制往往是我們感興趣的東西,而這些東西又沒有被文檔化,所以我們只能使用Microsoft提供的工具自己研究了。

首先,在基本Win32工程代碼中,我們可以直接看到消息處理函數、消息循環,所以建立一個基本Win32工程(本篇文章使用VS2005),爲了看到更多信息,我們需要進行設置,讓VS2005載入Microsoft的Symbol(pdb)文件[1]。爲了方便,去除了一些多餘的代碼,加入了兩個菜單,ID分別爲:IDM_SENDMESSAGE、IDM_POSTMESSAGE。如下列出經過簡化後的必要的代碼。

消息循環:

Ln000:while (GetMessage(&msg, NULL, 0, 0))

Ln001:{

Ln002:    TranslateMessage(&msg);

Ln003:    DispatchMessage(&msg);

Ln004:}

 

消息處理函數:

Ln100:LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)

Ln101:{

Ln102:    int wmId, wmEvent;

Ln103:    switch (message)

Ln104:    {

Ln105:    case WM_COMMAND:

Ln106:        wmId = LOWORD(wParam);

Ln107:        wmEvent = HIWORD(wParam);

Ln108:        switch (wmId)

Ln109:        {

Ln110:        case IDM_EXIT:

Ln111:            DestroyWindow(hWnd);

Ln112:            break;

Ln113:        case IDM_SENDMESSAGE:

Ln114:            SendMessage(hWnd, WM_SENDMESSAGE, 0, 0);

Ln115:            break;

Ln116:        case IDM_POSTMESSAGE:

Ln117:            PostMessage(hWnd, WM_POSTMESSAGE, 0, 0);

Ln118:            break;

Ln119:        default:

Ln120:            return DefWindowProc(hWnd, message, wParam, lParam);

Ln121:        }

Ln122:        break;

Ln123:

Ln124:    case WM_SENDMESSAGE:

Ln125:        MessageBox(hWnd, L"SendMessage", L"Prompt", MB_OK);

Ln126:        break;

Ln127:

Ln128:    case WM_POSTMESSAGE:

Ln129:        MessageBox(hWnd, L"PostMessage", L"Prompt", MB_OK);

Ln130:        break;

Ln131:

Ln132:    case WM_DESTROY:

Ln133:        PostQuitMessage(0);

Ln134:

Ln135:    default:

Ln136:        return DefWindowProc(hWnd, message, wParam, lParam);

Ln137:    }

Ln138:    return 0;

Ln139:}


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