久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

SendMessage、PostMessage原理

 魔音工作室 2012-12-10
SendMessage,、PostMessage原理
2011-02-12 16:02:29

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ì)于寫(xiě)一般Windows程序的程序員來(lái)說(shuō),,能夠這樣理解也就足夠了。但SendMessage,、PostMessage真的是一個(gè)發(fā)送消息等待,、一個(gè)發(fā)送消息不等待嗎?具體細(xì)節(jié),,下面第2點(diǎn)將會(huì)講到,。
 
2SendMessage,、PostMessage的運(yùn)行內(nèi)幕
在寫(xiě)一般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的解釋?zhuān)篢he 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)的線(xiàn)程中,,并立刻返回不等待線(xiàn)程處理消息。
仔細(xì)看完MSDN解釋?zhuān)覀兞私獾?,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提供的工具自己研究了。
首先,,在基本Win32工程代碼中,,我們可以直接看到消息處理函數(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),F(xiàn)5進(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),,F(xiàn)5 繼續(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,F(xiàn)10下一步,,可以看到并沒(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ì)話(huà)框,,點(diǎn)擊對(duì)話(huà)框中的確定后,,運(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),,F(xiàn)5進(jìn)行調(diào)試,,此處結(jié)果跟 SendMessage 一樣,不再說(shuō)明,。
第二步,,去除第一步下的斷點(diǎn),在 WndProc(Ln101) 函數(shù)入口處下個(gè)斷點(diǎn),,F(xiàn)5 繼續(xù)運(yùn)行,,此處結(jié)果跟 SendMessage 一樣,不再說(shuō)明,。
第三步,,去除第二步下的斷點(diǎn),在 Ln003,、Ln117,、Ln118、Ln129 處分別下一個(gè)斷點(diǎn),,在菜單中選擇對(duì)應(yīng)項(xiàng),,使程序運(yùn)行至 Ln117,F(xiàn)10 下一步,,可以看到已經(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)行處理,。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶(hù)發(fā)布,,不代表本站觀(guān)點(diǎn),。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,,謹(jǐn)防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào),。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶(hù) 評(píng)論公約

    類(lèi)似文章 更多