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

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

生活随笔

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

编程问答

消息机制(GUI线程讲解)

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

文章目錄

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

前奏

首先我們來(lái)畫(huà)一個(gè)窗口:

窗口代碼

#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);//畫(huà)刷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; //畫(huà)在哪HDC hdc; //顯卡緩存//設(shè)置窗口參數(shù):長(zhǎng)寬高之類(lèi)的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;//畫(huà)在哪hwnd = GetDesktopWindow();//hwnd=FindWindow("notepad.exe",NULL);//獲取DC設(shè)備句柄:可以把DC理解成顯卡緩存hdc = GetWindowDC(hwnd);cMessage = getchar();for(;;) {//畫(huà)窗口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;}} }


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

你能回答這些問(wèn)題嗎?

  • 什么是窗口句柄?在哪里?有什么用?
  • 什么是消息?什么是消息隊(duì)列?消息隊(duì)列在哪 ?
  • 什么是窗口過(guò)程?窗口過(guò)程是由誰(shuí)調(diào)用的?沒(méi)有消息循環(huán)窗口過(guò)程會(huì)執(zhí)行嗎?
  • 為什么要有w32k.sys這個(gè)模塊?
  • 為什么只有使用圖形界面的程序才可以訪問(wèn)KeServiceDescriptorTableShadow?
  • 界面“卡死”的時(shí)候?yàn)槭裁词髽?biāo)還可以動(dòng)?
  • 消息隊(duì)列:

    消息隊(duì)列在何處呢?

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

    那么Windows如何解決的呢?

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

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

    窗口句柄HWN

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

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

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

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

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

    重點(diǎn):

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

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

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

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

    總結(jié):

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

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

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