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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

从内核层说清GetMessage , DispatchMessage

發布時間:2025/3/21 60 豆豆
生活随笔 收集整理的這篇文章主要介紹了 从内核层说清GetMessage , DispatchMessage 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

    • 要點回顧:
    • 為什么拿到句柄非得要回零環?
    • 消息隊列(總共有7個小隊列)結構
    • GetMessage的聲明:
    • GetMessage進入內核:
    • GetMessage的功能總結:
    • DispatchMessage
    • 舉例驗證(有前提情況,仔細觀察)
    • ```SendMessage```發送消息運行截圖
    • ```PostMessage```發送消息運行截圖

要點回顧:

一個GUI線程有一個消息隊列:
普通線程–>GUI線程–>THREAD.W32THREAD -->THREADINFO–>消息隊列

一個線程可以有多個窗口,所有窗口共享一個消息隊列:
_WINDOW_OBJECT ---->PTHREADINFO pti //所屬線程
---->WNDPROC IpfnWndProc //窗口過程(窗口回調函數)

為什么拿到句柄非得要回零環?

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

這里消息msg的結構體成員如下:

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

這個消息里面存放著窗口的句柄,句柄是什么?句柄它僅僅是一個窗口對象的索引而已,并非當前對象地址,通過句柄找不到相應的窗口回調,它僅僅就是一個窗口對象索引值。窗口回調是存儲在窗口對象里面的,如果需要找到窗口回調,那么我們就需要先找到窗口對象,而窗口對象在哪呢?(窗口與線程的關系)窗口都是由API進入零環去畫出來,一切信息都在零環,這個知識點我們在前面已經說過。。

所以GetMessage,TranslateMessage,DispatchMessage拿著取出來的消息的句柄,進入零環,通過句柄找到相應的窗口對象,通過窗口對象找到相對于的窗口回調函數,然后內核進行調用回調函數。

這也就是為什么非得進入零環的原因。

消息隊列(總共有7個小隊列)結構

1.SentMessagesListHead //接到SendMessage發來的消息
2.PostedMessagesListHead //接到PostMessage發來的消息
3.HardwareMessagesListHead //接到鼠標,鍵盤的消息
…………
…………
根據前面的介紹,消息隊列放在THREADINFO(THREADINFO在KTHREAD結構體中,KTHREAD又在ETHREAD中)中:

USER_MESSAGE_QUEUE又分為七個小隊列

GetMessage的聲明:

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

GetMessage進入內核:

GetMessage會調用內核層函數w32k!NtUserGetMessage,偽代碼如下:

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

進入后可以查看到這里有處理SentMessagesListHead 消息隊列的函數:

然后進入后這是從0環回到3環的函數:

GetMessage只處理SendMessage發來的消息,原因可以看上圖,而由PostMessage發來的消息,只是取出,并不會進行近一步處理操作

GetMessage的功能總結:

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

  • (第一個循環)首先會判斷SentMessagesListHead 這個隊列里面有沒有消息,如果有的話,首先會把這個消息給處理掉(如何處理呢?也就是從0環回到3環,再來調用注冊的窗口過程函數)
  • (第二個循環:依次判斷其他的6個隊列,里面如果有消息,就返回,沒有就繼續取消息)循環判斷是否有該窗口的消息,如果有,將消息存儲到MSG指定的結構,并將消息從列表中刪除(依次判斷其他的6個隊列,里面如果有消息 返回,沒有 繼續)
    它會首先看SentMessagesListHead 這個隊列,如果有的話,會就地處理
  • DispatchMessage

    DispatchMessage(&msg)//消息的分發,根據窗口句柄調用相關的窗口過程,通過不同的句柄,進入零環找到不同的窗口對象,然后根據窗口對象找到回調函數,并且調用回調函數。

    即其他6個消息隊列的處理流程:
    User32!DispatchMessage調用w32k!NtUserDispatchMessage

  • 根據窗口句柄找到窗口對象
  • 根據窗口對象找到窗口過程處理函數,由0環發起調用
  • 舉例驗證(有前提情況,仔細觀察)

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

    SendMessage發送消息運行截圖

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


    下圖中我們可以看到

    當我們未點擊確定時,發送消息的程序未退出,需要點擊確定后,發送消息的程序收到返回消息,它才會自行退出。這也就是SendMessage的同步問題

    當點擊確定后,發送消息程序的運行截圖:

    PostMessage發送消息運行截圖

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

    發送消息的運行截圖:

    接收消息的運行截圖:

    這里充分說明了上述情況,GetMessage并不會處理PostMessage發送的消息。

    注意:
    PostMessage發送完消息后,程序即刻退出,并不會等待處理結果,這也就是PostMessage發送消息異步問題

    總結

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

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。