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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

消息机制(GUI线程讲解)

發(fā)布時間:2025/3/21 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 消息机制(GUI线程讲解) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

文章目錄

    • 前奏
    • 窗口代碼
    • 你能回答這些問題嗎?
    • 消息隊列:
    • 消息隊列在何處呢?
    • 那么Windows如何解決的呢?
    • 重點:
    • 總結(jié):

前奏

首先我們來畫一個窗口:

窗口代碼

#include<Windows.h> #include <stdio.h> #define _WIN32_WINNT 0x0500typedef struct _Color {DWORD r;DWORD g;DWORD b; }Color;typedef struct _WindowClass {DWORD x;DWORD y;DWORD width;DWORD hight;Color color; }WindowClass;void PaintWindwos(HDC hdc, WindowClass* p) {HBRUSH hBrush;hBrush = (HBRUSH)GetStockObject(DC_BRUSH);SelectObject(hdc, hBrush);//畫刷SetDCBrushColor(hdc, RGB(p->color.r, p->color.g, p->color.b));MoveToEx(hdc, p->x, p->y, NULL);LineTo(hdc, p->x + p->width, p->y);LineTo(hdc, p->x + p->width, p->y + p->hight);LineTo(hdc, p->x, p->y + p->hight);LineTo(hdc, p->x, p->y);Rectangle(hdc, p->x, p->y, p->x + p->width, p->y + p->width + 1);DeleteObject(hBrush); } void main() {char cMessage; //消息HWND hwnd; //畫在哪HDC hdc; //顯卡緩存//設置窗口參數(shù):長寬高之類的WindowClass wClass;wClass.x = 0;wClass.y = 0;wClass.width = 800;wClass.hight = 400;wClass.color.r = 0xEF;wClass.color.g = 0xEB;wClass.color.b = 0xDE;//畫在哪hwnd = GetDesktopWindow();//hwnd=FindWindow("notepad.exe",NULL);//獲取DC設備句柄:可以把DC理解成顯卡緩存hdc = GetWindowDC(hwnd);cMessage = getchar();for(;;) {//畫窗口PaintWindwos(hdc, &wClass);//接收消息switch (cMessage){case 'a':wClass.color.r += 0x10;wClass.color.g += 0x10;wClass.color.b += 0x10;break;case 'b':wClass.color.r += 0x20;wClass.color.g += 0x20;wClass.color.b += 0x20;break;default:break;}} }


在這里呢我們可以通過控制臺去控制窗口的顏色,那么接下來讓我們一起來看看原理:

你能回答這些問題嗎?

  • 什么是窗口句柄?在哪里?有什么用?
  • 什么是消息?什么是消息隊列?消息隊列在哪 ?
  • 什么是窗口過程?窗口過程是由誰調(diào)用的?沒有消息循環(huán)窗口過程會執(zhí)行嗎?
  • 為什么要有w32k.sys這個模塊?
  • 為什么只有使用圖形界面的程序才可以訪問KeServiceDescriptorTableShadow?
  • 界面“卡死”的時候為什么鼠標還可以動?
  • 消息隊列:

    消息隊列在何處呢?

    首先我們假設把消息隊列放在用戶空間(3環(huán)),那么誰又來往用戶空間的消息隊列存儲這些東西呢?
    最好的解決方案就是找一個專用進程來監(jiān)聽鼠標和鍵盤等,再來進行判斷是屬于哪個進程的消息隊列,最后來進行消息分發(fā)(Linux解決方案)
    弊端:涉及了跨進程通信問題,專用進程傳給其它進程。大量時間都花在跨進程。

    那么Windows如何解決的呢?

    首先普及一下:
    kernel32.dll ----------> ntoskrnl.exe(進程,線程,內(nèi)存管
    user32.dll gdi32.dll -----------> win32k.sys(圖形界面,消息管理)

    Windows已經(jīng)畫好的界面(windows提供的)GUI編程 user32.dll
    不用Windows提供的那些界面 GDI編程 gdi32.dll

    窗口句柄HWN

    針對窗口的句柄表,只有一個,(放在內(nèi)核中)表是全局的,所有窗口共用的

    HDC hdc; HPEN hpen; 1.設備對象 畫在哪 hwnd =(HWND)0x0003543; 2.獲取設備對象上下文 hdc=GetDC(hwnd); 3.創(chuàng)建畫筆 設置線條屬性 hpen=CreatePen(PS_S0LID,5,RGB(0xFF,00,00)); 4.關(guān)聯(lián) SelectObject(hdc,hpen); 5.開始畫 LineTo(hdc,400,400);//gdi32.dll 6.釋放資源 DeleteObject(hpen); ReleaseDC(hwnd,hdc);

    它把消息隊列放在(內(nèi)核空間)0環(huán)中,

    微軟的解決方案:GUI線程
    GUI(自己使用微軟提供的窗口函數(shù),比如CreateWindow,CreateButton等創(chuàng)建的圖形界面,這種API就叫做GUI)

    GDI(如果覺得微軟提供的窗口不符合自己所需條件,需要自己畫,所用的那些API就叫GDI)

    重點:

    1.當線程剛創(chuàng)建的時候,都是普通線程:
    Thread.ServiceTable -->KeServiceDescriptorTable(SSDT表)
    ServiceTable中存儲了一張表,叫做系統(tǒng)服務表

    2.當線程第一次調(diào)用(與圖形界面相關(guān)的模塊 )Win32k.sys時(只要試圖正常調(diào)用Win32k中的任何一個函數(shù)),會調(diào)用一個函數(shù):PsConvertToGuiThread(把普通線程轉(zhuǎn)換為GUI線程)

    PsConvertToGuiThread主要做幾件事:
    a.擴充內(nèi)核棧,必須換成64KB 的大內(nèi)核棧,因為普通內(nèi)核棧只有12KB大小。
    b.創(chuàng)建一個包含消息隊列的結(jié)構(gòu)體,并掛到KTHREAD上(也就是KTHREAD中的Win32Thread)
    c.Thread.ServiceTable–>KeServiceDescriptorShadow(SSDTShadow表)
    d.把需要的內(nèi)存數(shù)據(jù)映射到本進程空間

    (SSDT表中只引用了一張表,只有一張系統(tǒng)服務表,也就是ntoskernel,win32k的第二張表它沒有。但是SSDTShaow表中既包含了ntoskernel中的函數(shù),又包含了Win32k(與圖形界面相關(guān)的)中的函數(shù))
    解釋:
    如果是一個普通線程的話,那么ETHRED結(jié)構(gòu)體中成員KTHREAD結(jié)構(gòu)體中有一個Win32Thread成員它是為空(未使用圖形界面相關(guān)的API)
    如果是一個GUI線程的話,那么ETHRED結(jié)構(gòu)體中成員KTHREAD有一個Win32Thread成員它是一個地址值,指向一個結(jié)構(gòu)體,指向一個_THREADINFO結(jié)構(gòu)體,這個結(jié)構(gòu)體里面又有一個成員,存放著消息隊列

    總結(jié):

  • 消息隊列存儲在0環(huán),通過KTHREAD.Win32Thread可以找到
  • 并不是所有線程都要消息隊列,只有GUI線程才有消息隊列
  • 一個GUI線程對應1個消息隊列
  • 總結(jié)

    以上是生活随笔為你收集整理的消息机制(GUI线程讲解)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

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