日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) >

SendMessage、PostMessage原理

發(fā)布時(shí)間:2025/3/20 47 豆豆
生活随笔 收集整理的這篇文章主要介紹了 SendMessage、PostMessage原理 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

SendMessage、PostMessage原理

本文講解SendMessage、PostMessage兩個(gè)函數(shù)的實(shí)現(xiàn)原理,分為三個(gè)步驟進(jìn)行講解,分別適合初級(jí)、中級(jí)、高級(jí)程序員進(jìn)行理解,三個(gè)步驟分別為:

1、SendMessage、PostMessage的運(yùn)行機(jī)制。

2、SendMessage、PostMessage的運(yùn)行內(nèi)幕。

3、SendMessage、PostMessage的內(nèi)部實(shí)現(xiàn)。

注:理解這篇文章之前,必須先了解Windows的消息循環(huán)機(jī)制。

?

1、SendMessage、PostMessage的運(yùn)行機(jī)制

我們先來(lái)看最簡(jiǎn)單的。

SendMessage可以理解為,SendMessage函數(shù)發(fā)送消息,等待消息處理完成后,SendMessage才返回。稍微深入一點(diǎn),是等待窗口處理函數(shù)返回后,SendMessage就返回了。

PostMessage可以理解為,PostMessage函數(shù)發(fā)送消息,不等待消息處理完成,立刻返回。稍微深入一點(diǎn),PostMessage只管發(fā)送消息,消息有沒(méi)有被送到則并不關(guān)心,只要發(fā)送了消息,便立刻返回。

對(duì)于寫一般Windows程序的程序員來(lái)說(shuō),能夠這樣理解也就足夠了。但SendMessage、PostMessage真的是一個(gè)發(fā)送消息等待、一個(gè)發(fā)送消息不等待嗎?具體細(xì)節(jié),下面第2點(diǎn)將會(huì)講到。

?

2、SendMessage、PostMessage的運(yùn)行內(nèi)幕

在寫一般Windows程序時(shí),如上第1點(diǎn)講到的足以應(yīng)付,其實(shí)我們可以看看MSDN來(lái)確定SendMessage、PostMessage的運(yùn)行內(nèi)幕。

在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函數(shù)將指定的消息發(fā)到窗口。它調(diào)用特定窗口的窗口處理函數(shù),并且不會(huì)立即返回,直到窗口處理函數(shù)處理了這個(gè)消息。

再看看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函數(shù)將一個(gè)消息放入與創(chuàng)建這個(gè)窗口的消息隊(duì)列相關(guān)的線程中,并立刻返回不等待線程處理消息。

仔細(xì)看完MSDN解釋,我們了解到,SendMessage的確是發(fā)送消息,然后等待處理完成返回,但發(fā)送消息的方法為直接調(diào)用消息處理函數(shù)(即WndProc函數(shù)),按照函數(shù)調(diào)用規(guī)則,肯定會(huì)等消息處理函數(shù)返回之后,SendMessage才返回。而PostMessage卻沒(méi)有發(fā)送消息,PostMessage是將消息放入消息隊(duì)列中,然后立刻返回,至于消息何時(shí)被處理,PostMessage完全不知道,此時(shí)只有消息循環(huán)知道被PostMessage的消息何時(shí)被處理了。

至此我們撥開(kāi)了一層疑云,原來(lái)SendMessage只是調(diào)用我們的消息處理函數(shù),PostMessage只是將消息放到消息隊(duì)列中。下一節(jié)將會(huì)更深入這兩個(gè)函數(shù),看看Microsoft究竟是如何實(shí)現(xiàn)這兩個(gè)函數(shù)的。

?

3、SendMessage、PostMessage的內(nèi)部實(shí)現(xiàn)

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

首先,在基本W(wǎng)in32工程代碼中,我們可以直接看到消息處理函數(shù)、消息循環(huán),所以建立一個(gè)基本W(wǎng)in32工程(本篇文章使用VS2005),為了看到更多信息,我們需要進(jìn)行設(shè)置,讓VS2005載入Microsoft的Symbol(pdb)文件[1]。為了方便,去除了一些多余的代碼,加入了兩個(gè)菜單,ID分別為:IDM_SENDMESSAGE、IDM_POSTMESSAGE。如下列出經(jīng)過(guò)簡(jiǎn)化后的必要的代碼。

消息循環(huán):

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

Ln001:{

Ln002:??? TranslateMessage(&msg);

Ln003:??? DispatchMessage(&msg);

Ln004:}

?

消息處理函數(shù):

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:}

?

??? 下面一步步分析這兩個(gè)函數(shù)的內(nèi)部情況,先討論 SendMessage。

第一步,在DispatchMessage(Ln003)函數(shù)處下個(gè)斷點(diǎn),F5進(jìn)行調(diào)試,當(dāng)程序運(yùn)行到斷點(diǎn)后,查看 CallStack 窗口,可得如下結(jié)果:

#003:MyProj.exe!wWinMain(HINSTANCE__ * hInstance=0x00400000, HINSTANCE__ * hPrevInstance=0x00000000, wchar_t * lpCmdLine=0x000208e0, int nCmdShow=0x00000001)? Line 49?? C++

#002:MyProj.exe!__tmainCRTStartup()? Line 589 + 0x35 bytes C

#001:MyProj.exe!wWinMainCRTStartup()? Line 414 C

#000:kernel32.dll!_BaseProcessStart@4()? + 0x23 bytes?

我們可以看到,進(jìn)程先調(diào)用 kernel32.dll 中的 BaseProcessStart 函數(shù),然后調(diào)用的 Startup Code 的函數(shù) wWinMainCRTStartup,然后調(diào)用 _tmainCRTStartup 函數(shù),最終調(diào)用我們的 wWinMain 函數(shù),我們的程序就運(yùn)行起來(lái)了。

?

第二步,去除第一步下的斷點(diǎn),在 WndProc(Ln101) 函數(shù)入口處下個(gè)斷點(diǎn),F5 繼續(xù)運(yùn)行,運(yùn)行到新下的斷點(diǎn)處,查看 CallStack 窗口,可得如下結(jié)果:

#008:MyProj.exe!WndProc(HWND__ * hWnd=0x00050860, unsigned int message=0x00000101, unsigned int wParam=0x00000074, long lParam=0xc03f0001)? Line 122??? C++

#007:user32.dll!_InternalCallWinProc@20()? + 0x28 bytes???

#006:user32.dll!_UserCallWinProcCheckWow@32()? + 0xb7 bytes???

#005:user32.dll!_DispatchMessageWorker@8()? + 0xdc bytes??

#004:user32.dll!_DispatchMessageW@4()? + 0xf bytes

#003:MyProj.exe!wWinMain(HINSTANCE__ * hInstance=0x00400000, HINSTANCE__ * hPrevInstance=0x00000000, wchar_t * lpCmdLine=0x000208e0, #000:int nCmdShow=0x00000001)? Line 49 + 0xc bytes C++

#002:MyProj.exe!__tmainCRTStartup()? Line 589 + 0x35 bytes C

#001:MyProj.exe!wWinMainCRTStartup()? Line 414 C

#000:kernel32.dll!_BaseProcessStart@4()? + 0x23 bytes?

??? #000~#003 跟第一步相同,不再解釋。在 #004、#005,可以看到,函數(shù)運(yùn)行到 DispatchMessage 的內(nèi)部了,DispatchMessageW、DispatchMessageWorker 是 user32.dll 中到處的函數(shù),而且函數(shù)前部字符串相等,在此猜想應(yīng)該是 DispatchMessage 的內(nèi)部處理。#008 為我們消息處理函數(shù),所以推想而知,#006、#007 是為了調(diào)用我們的消息處理函數(shù)而準(zhǔn)備的代碼。

?

第三步,去除第二步下的斷點(diǎn),在Ln003、Ln114、Ln115、Ln125 處分別下一個(gè)斷點(diǎn),在菜單中選擇對(duì)應(yīng)項(xiàng),使程序運(yùn)行至 Ln114,F10下一步,可以看到并沒(méi)有運(yùn)行到 break(Ln115),直接跳到了 Ln125 處,由此可知目前 SendMessage 已經(jīng)在等待了,查看 CallStack 窗口,可得如下結(jié)果:

#013:MyProj.exe!WndProc(HWND__ * hWnd=0x00050860, unsigned int message=0x00000500, unsigned int wParam=0x00000000, long lParam=0x00000000)? Line 147??? C++

#012:user32.dll!_InternalCallWinProc@20()? + 0x28 bytes???

#011:user32.dll!_UserCallWinProcCheckWow@32()? + 0xb7 bytes???

#010:user32.dll!_SendMessageWorker@20()? + 0xc8 bytes?

#009:user32.dll!_SendMessageW@16()? + 0x49 bytes??

#008:MyProj.exe!WndProc(HWND__ * hWnd=0x00050860, unsigned int message=0x00000111, unsigned int wParam=0x00008003, long lParam=0x00000000)? Line 136 + 0x15 bytes?? C++

#007:user32.dll!_InternalCallWinProc@20()? + 0x28 bytes???

#006:user32.dll!_UserCallWinProcCheckWow@32()? + 0xb7 bytes???

#005:user32.dll!_DispatchMessageWorker@8()? + 0xdc bytes??

#004:user32.dll!_DispatchMessageW@4()? + 0xf bytes

#003:MyProj.exe!wWinMain(HINSTANCE__ * hInstance=0x00400000, HINSTANCE__ * hPrevInstance=0x00000000, wchar_t * lpCmdLine=0x000208e0, #000:int nCmdShow=0x00000001)? Line 49 + 0xc bytes C++

#002:MyProj.exe!__tmainCRTStartup()? Line 589 + 0x35 bytes C

#001:MyProj.exe!wWinMainCRTStartup()? Line 414 C

#000:kernel32.dll!_BaseProcessStart@4()? + 0x23 bytes?

#000~#008 跟上面的相同,不再解釋。在 #009、#010,可以看到,函數(shù)調(diào)用到 SendMessage 內(nèi)部了,在此猜想應(yīng)該是 SendMessage 的內(nèi)部處理。#011、#012 跟第二步中的 #006、#007 一樣,在第二部中,這兩個(gè)函數(shù)是為了調(diào)用消息處理函數(shù)而準(zhǔn)備的代碼,#013 也是我們的消息處理函數(shù),所以此兩行代碼的功能相等。

至此,我們證明了 SendMessage 的確是直接調(diào)用消息處理函數(shù)的,在消息處理函數(shù)返回前,SendMessage 等待。在所有的操作中,Ln003 斷點(diǎn)沒(méi)有去到,證明 SendMessage 不會(huì)將消息放入消息隊(duì)列中(在 PostMessage 分析中,此斷點(diǎn)將會(huì)跑到,接下來(lái)講述)。

?

第四步,F5繼續(xù)運(yùn)行,此時(shí)彈出對(duì)話框,點(diǎn)擊對(duì)話框中的確定后,運(yùn)行到斷點(diǎn) Ln115 處。查看 CallStack 窗口,可得如下結(jié)果:

#008:MyProj.exe!WndProc(HWND__ * hWnd=0x00050860, unsigned int message=0x00000111, unsigned int wParam=0x00008003, long lParam=0x00000000)? Line 137??? C++

#007:user32.dll!_InternalCallWinProc@20()? + 0x28 bytes???

#006:user32.dll!_UserCallWinProcCheckWow@32()? + 0xb7 bytes???

#005:user32.dll!_DispatchMessageWorker@8()? + 0xdc bytes??

#004:user32.dll!_DispatchMessageW@4()? + 0xf bytes

#003:MyProj.exe!wWinMain(HINSTANCE__ * hInstance=0x00400000, HINSTANCE__ * hPrevInstance=0x00000000, wchar_t * lpCmdLine=0x000208e0, int nCmdShow=0x00000001)? Line 49 + 0xc bytes?? C++

#002:MyProj.exe!__tmainCRTStartup()? Line 589 + 0x35 bytes C

#001:MyProj.exe!wWinMainCRTStartup()? Line 414 C

#000:kernel32.dll!_BaseProcessStart@4()? + 0x23 bytes?

#000~008 跟第二步的完全相同,此時(shí) SendMessage 也已經(jīng)返回,所調(diào)用的堆棧也清空了。

至此,我們徹底撥開(kāi)了 SendMessage 的疑云,了解了 SendMessage 函數(shù)的運(yùn)行機(jī)制,綜述為,SendMessage 內(nèi)部調(diào)用 SendMessageW、SendMessageWorker 函數(shù)做內(nèi)部處理,然后調(diào)用 UserCallWinProcCheckWow、InternalCallWinProc 來(lái)調(diào)用我們代碼中的消息處理函數(shù),消息處理函數(shù)完成之后,SendMessage 函數(shù)便返回了。

?

SendMessage 討論完之后,現(xiàn)在討論 PostMessage,將上面的所有斷點(diǎn)刪除,關(guān)閉調(diào)試。

第一步,在DispatchMessage(Ln003)函數(shù)處下個(gè)斷點(diǎn),F5進(jìn)行調(diào)試,此處結(jié)果跟 SendMessage 一樣,不再說(shuō)明。

第二步,去除第一步下的斷點(diǎn),在 WndProc(Ln101) 函數(shù)入口處下個(gè)斷點(diǎn),F5 繼續(xù)運(yùn)行,此處結(jié)果跟 SendMessage 一樣,不再說(shuō)明。

第三步,去除第二步下的斷點(diǎn),在 Ln003、Ln117、Ln118、Ln129 處分別下一個(gè)斷點(diǎn),在菜單中選擇對(duì)應(yīng)項(xiàng),使程序運(yùn)行至 Ln117,F10 下一步,可以看到已經(jīng)運(yùn)行到 break,PostMessage 函數(shù)返回了,此時(shí) CallStack 沒(méi)有變化。

第四步,F5 繼續(xù)運(yùn)行,此時(shí)程序運(yùn)行到 Ln003,CallStack 跟第一步剛起來(lái)時(shí)一樣。

第五步,F5 繼續(xù)運(yùn)行(由于有多個(gè)消息,可能要按多次),讓程序運(yùn)行到 Ln129,此時(shí) CallStack 跟第二步相同,為了方便說(shuō)明,再次列舉如下:

#008:MyProj.exe!WndProc(HWND__ * hWnd=0x00070874, unsigned int message=0x00000501, unsigned int wParam=0x00000000, long lParam=0x00000000)? Line 151??? C++

#007:user32.dll!_InternalCallWinProc@20()? + 0x28 bytes???

#006:user32.dll!_UserCallWinProcCheckWow@32()? + 0xb7 bytes???

#005:user32.dll!_DispatchMessageWorker@8()? + 0xdc bytes??

#004:user32.dll!_DispatchMessageW@4()? + 0xf bytes

#003:MyProj.exe!wWinMain(HINSTANCE__ * hInstance=0x00400000, HINSTANCE__ * hPrevInstance=0x00000000, wchar_t * lpCmdLine=0x000208e0, int nCmdShow=0x00000001)? Line 49 + 0xc bytes?? C++

#002:MyProj.exe!__tmainCRTStartup()? Line 589 + 0x35 bytes C

#001:MyProj.exe!wWinMainCRTStartup()? Line 414 C

#000:kernel32.dll!_BaseProcessStart@4()? + 0x23 bytes?

由此可以看到,此調(diào)用是從消息循環(huán)中調(diào)用而來(lái),DispatchMessageW、DispatchMessageWorker 是 DispatchMessage 的內(nèi)部處理,UserCallWinProcCheckWow、InternalCallWinProc是為了調(diào)用我們的消息處理函數(shù)而準(zhǔn)備的代碼。

至此,我們?cè)俅螐氐讚荛_(kāi)了 PostMessage 的疑云,了解了 PostMessage 函數(shù)的運(yùn)行機(jī)制,綜述為,PostMessage 將消息放入消息隊(duì)列中,自己立刻返回,消息循環(huán)中的 GetMessage(PeekMessage 也可,本例中為演示)處理到我們發(fā)的消息之后,便按照普通消息處理方法進(jìn)行處理。

?

?

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

[1]關(guān)于如何設(shè)置,讓VS2005載入Symbol,可以查看我寫的另外一篇文章:“讓Visual Studio載入Symbol(pdb)文件”,地址:http://blog.csdn.net/xt_xiaotian/archive/2010/03/16/5384111.aspx

?

本文來(lái)自CSDN博客,轉(zhuǎn)載請(qǐng)標(biāo)明出處:http://blog.csdn.net/xt_xiaotian/archive/2010/03/16/5384137.aspx

總結(jié)

以上是生活随笔為你收集整理的SendMessage、PostMessage原理的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。