日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

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

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

从内核层说清GetMessage , DispatchMessage

發(fā)布時(shí)間:2025/3/21 编程问答 54 豆豆
生活随笔 收集整理的這篇文章主要介紹了 从内核层说清GetMessage , DispatchMessage 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

文章目錄

    • 要點(diǎn)回顧:
    • 為什么拿到句柄非得要回零環(huán)?
    • 消息隊(duì)列(總共有7個(gè)小隊(duì)列)結(jié)構(gòu)
    • GetMessage的聲明:
    • GetMessage進(jìn)入內(nèi)核:
    • GetMessage的功能總結(jié):
    • DispatchMessage
    • 舉例驗(yàn)證(有前提情況,仔細(xì)觀察)
    • ```SendMessage```發(fā)送消息運(yùn)行截圖
    • ```PostMessage```發(fā)送消息運(yùn)行截圖

要點(diǎn)回顧:

一個(gè)GUI線程有一個(gè)消息隊(duì)列:
普通線程–>GUI線程–>THREAD.W32THREAD -->THREADINFO–>消息隊(duì)列

一個(gè)線程可以有多個(gè)窗口,所有窗口共享一個(gè)消息隊(duì)列:
_WINDOW_OBJECT ---->PTHREADINFO pti //所屬線程
---->WNDPROC IpfnWndProc //窗口過(guò)程(窗口回調(diào)函數(shù))

為什么拿到句柄非得要回零環(huán)?

GetMessage(&msg, NULL, 0, 0) TranslateMessage(&msg); DispatchMessage(&msg);

這里消息msg的結(jié)構(gòu)體成員如下:

typedef struct tagMSG {HWND hwnd;UINT message;WPARAM wParam;LPARAM lParam;DWORD time;POINT pt;DWORD lPrivate; } MSG, *PMSG, *NPMSG, *LPMSG;

這個(gè)消息里面存放著窗口的句柄,句柄是什么?句柄它僅僅是一個(gè)窗口對(duì)象的索引而已,并非當(dāng)前對(duì)象地址,通過(guò)句柄找不到相應(yīng)的窗口回調(diào),它僅僅就是一個(gè)窗口對(duì)象索引值。窗口回調(diào)是存儲(chǔ)在窗口對(duì)象里面的,如果需要找到窗口回調(diào),那么我們就需要先找到窗口對(duì)象,而窗口對(duì)象在哪呢?(窗口與線程的關(guān)系)窗口都是由API進(jìn)入零環(huán)去畫出來(lái),一切信息都在零環(huán),這個(gè)知識(shí)點(diǎn)我們?cè)谇懊嬉呀?jīng)說(shuō)過(guò)。。

所以GetMessage,TranslateMessage,DispatchMessage拿著取出來(lái)的消息的句柄,進(jìn)入零環(huán),通過(guò)句柄找到相應(yīng)的窗口對(duì)象,通過(guò)窗口對(duì)象找到相對(duì)于的窗口回調(diào)函數(shù),然后內(nèi)核進(jìn)行調(diào)用回調(diào)函數(shù)。

這也就是為什么非得進(jìn)入零環(huán)的原因。

消息隊(duì)列(總共有7個(gè)小隊(duì)列)結(jié)構(gòu)

1.SentMessagesListHead //接到SendMessage發(fā)來(lái)的消息
2.PostedMessagesListHead //接到PostMessage發(fā)來(lái)的消息
3.HardwareMessagesListHead //接到鼠標(biāo),鍵盤的消息
…………
…………
根據(jù)前面的介紹,消息隊(duì)列放在THREADINFO(THREADINFO在KTHREAD結(jié)構(gòu)體中,KTHREAD又在ETHREAD中)中:

USER_MESSAGE_QUEUE又分為七個(gè)小隊(duì)列

GetMessage的聲明:

GetMessage(LPMSG IpMsg, //返回從隊(duì)列中摘下來(lái)的消息HWND hWnd, //過(guò)濾條件一:(要取的是哪個(gè)窗口的消息,如果要專門取哪個(gè)窗口的消息,直接把句柄放在此處就行)發(fā)個(gè)這個(gè)窗口的消息UINT wMsgFilterMin, //過(guò)濾條件UINT wMsgFilterMax //過(guò)濾條件;

GetMessage進(jìn)入內(nèi)核:

GetMessage會(huì)調(diào)用內(nèi)核層函數(shù)w32k!NtUserGetMessage,偽代碼如下:

do{ //先判斷SentMessageListHead do{ …… KeUserModeCallBack(USER32_CALLBACK_WINDOWPROC,Arguments,ArgumentLength,&ResultPointer,&ResultLength); ………… }while(SentMessageListHead!=NULL}while(其他隊(duì)列!=NULL

進(jìn)入后可以查看到這里有處理SentMessagesListHead 消息隊(duì)列的函數(shù):

然后進(jìn)入后這是從0環(huán)回到3環(huán)的函數(shù):

GetMessage只處理SendMessage發(fā)來(lái)的消息,原因可以看上圖,而由PostMessage發(fā)來(lái)的消息,只是取出,并不會(huì)進(jìn)行近一步處理操作

GetMessage的功能總結(jié):

GetMessage(只處理第一個(gè)消息隊(duì)列的消息,至于其它消息隊(duì)列的消息,GetMessage只負(fù)責(zé)取出, 然后不管,繼續(xù)向下傳遞)的主要功能:

  • (第一個(gè)循環(huán))首先會(huì)判斷SentMessagesListHead 這個(gè)隊(duì)列里面有沒(méi)有消息,如果有的話,首先會(huì)把這個(gè)消息給處理掉(如何處理呢?也就是從0環(huán)回到3環(huán),再來(lái)調(diào)用注冊(cè)的窗口過(guò)程函數(shù))
  • (第二個(gè)循環(huán):依次判斷其他的6個(gè)隊(duì)列,里面如果有消息,就返回,沒(méi)有就繼續(xù)取消息)循環(huán)判斷是否有該窗口的消息,如果有,將消息存儲(chǔ)到MSG指定的結(jié)構(gòu),并將消息從列表中刪除(依次判斷其他的6個(gè)隊(duì)列,里面如果有消息 返回,沒(méi)有 繼續(xù))
    它會(huì)首先看SentMessagesListHead 這個(gè)隊(duì)列,如果有的話,會(huì)就地處理
  • DispatchMessage

    DispatchMessage(&msg)//消息的分發(fā),根據(jù)窗口句柄調(diào)用相關(guān)的窗口過(guò)程,通過(guò)不同的句柄,進(jìn)入零環(huán)找到不同的窗口對(duì)象,然后根據(jù)窗口對(duì)象找到回調(diào)函數(shù),并且調(diào)用回調(diào)函數(shù)。

    即其他6個(gè)消息隊(duì)列的處理流程:
    User32!DispatchMessage調(diào)用w32k!NtUserDispatchMessage

  • 根據(jù)窗口句柄找到窗口對(duì)象
  • 根據(jù)窗口對(duì)象找到窗口過(guò)程處理函數(shù),由0環(huán)發(fā)起調(diào)用
  • 舉例驗(yàn)證(有前提情況,仔細(xì)觀察)

    把TranslateMessage(&msg);和DispatchMessage(&msg);注釋掉后,只剩GetMessage(&msg, NULL, 0, 0),然后利用其它程序PostMessage(hwnd, 0x0401, NULL, NULL);和SendMessage(hwnd, 0x0401, NULL, NULL);分別發(fā)送消息
    前提情況:(特別注意)

    SendMessage發(fā)送消息運(yùn)行截圖

    SendMessage(hwnd, 0x0401, NULL, NULL);


    下圖中我們可以看到

    當(dāng)我們未點(diǎn)擊確定時(shí),發(fā)送消息的程序未退出,需要點(diǎn)擊確定后,發(fā)送消息的程序收到返回消息,它才會(huì)自行退出。這也就是SendMessage的同步問(wèn)題

    當(dāng)點(diǎn)擊確定后,發(fā)送消息程序的運(yùn)行截圖:

    PostMessage發(fā)送消息運(yùn)行截圖

    PostMessage(hwnd, 0x0401, NULL, NULL);

    發(fā)送消息的運(yùn)行截圖:

    接收消息的運(yùn)行截圖:

    這里充分說(shuō)明了上述情況,GetMessage并不會(huì)處理PostMessage發(fā)送的消息。

    注意:
    PostMessage發(fā)送完消息后,程序即刻退出,并不會(huì)等待處理結(jié)果,這也就是PostMessage發(fā)送消息異步問(wèn)題

    總結(jié)

    以上是生活随笔為你收集整理的从内核层说清GetMessage , DispatchMessage的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

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