欢迎光临
我们一直在努力

窗口的本质

窗口的本质

  • 前置基础
    1)虚拟内存
    ● 每个进程 4GB 虚拟地址:0x00000000 ~ 0xFFFFFFFF
    ● 用户空间:0x00000000 ~ 0x7FFFFFFF(低 2GB,进程私有)
    ● 内核空间:0x80000000 ~ 0xFFFFFFFF(高 2GB,所有进程共享)
    2)模块划分
    ● 内核模块(内核空间)
    ○ ntoskrnl.exe:进程、线程、内存管理核心
    ○ win32k.sys:图形界面、窗口消息、GDI 底层实现,所有进程共享
    ● 用户模块(用户空间,每个进程独立)
    ○ kernel32.dll:进程线程内存基础 API
    ○ user32.dll:窗口、控件、消息
    ○ gdi32.dll:图形设备接口
    3)API 调用链路
    用户程序 → DLL 接口 (kernel32/user32/gdi32) → 内核模块真正实现
  • 句柄对比:HANDLE 与 HWND
  • 类型维护者句柄表跨进程生命周期用途
    HANDLE 各个内核对象 进程私有句柄表 ❌无效 进程关闭自动销毁 进程、线程、互斥体、事件等内核对象
    HWND win32k.sys 全局共享句柄表 ✅全系统有效 窗口销毁才失效 窗口、控件

    重点:HWND 是全局的,A 进程拿到的窗口句柄,B 进程可以直接使用
    4. GDI 绘图核心概念
    1)设备对象 (HWND) 绘图目标,代表 “画在哪里”,可以是窗口、桌面;Spy++ 可以抓取 HWND
    2)设备上下文 HDC(Device Context)
    内存绘图缓冲区,所有 GDI 绘图必须依赖 HDC
    ● 获取:HDC GetDC(HWND hwnd)
    ● 释放:ReleaseDC(HWND hwnd, HDC hdc)
    ● 双缓冲:先内存绘图,再输出到屏幕
    3)GDI 图形对象(选入 DC 使用)

    对象作用创建函数
    Pen 画笔 线条颜色、粗细、线型 CreatePen()
    Brush 画刷 区域填充颜色图案 CreateSolidBrush() / GetStockObject()
    Font 字体 文字样式 CreateFont()
    Bitmap 位图 图片 CreateBitmap()

    SelectObject(HDC hdc, HGDIOBJ hgdiobj)
    ● 将 GDI 对象选入 DC,返回旧对象句柄
    ● DC 同一时刻每类对象只能有一个生效
    ● 绘图完成要恢复旧对象,销毁自定义 GDI 对象,否则发生GDI 资源泄漏
    5. 画笔 CreatePen

    HPEN CreatePen(int style, int width, COLORREF color);

    线型:
    ○ PS_SOLID 实线
    ○ PS_DASH虚线、PS_DOT点线、PS_DASHDOT点划线
    虚线 / 点线,宽度必须≤1
    宽度:逻辑像素,填 0 代表强制 1 像素
    颜色:COLORREF RGB(r,g,b),r/g/b 范围 0‑255(FF)
    示例:CreatePen(PS_SOLID,5,RGB(255,0,0)); //5像素红色实线
    6. GetStockObject 获取系统预置 GDI 对象

    HGDIOBJ GetStockObject(int nIndex);

    常用参数:
    ● BLACK_BRUSH黑色画刷、WHITE_BRUSH白色画刷
    ● NULL_BRUSH / HOLLOW_BRUSH空心画刷
    ● DC_BRUSH可动态改色的画刷,配合SetDCBrushColor()
    系统预置对象不需要必须 DeleteObject,写 DeleteObject 也无害
    7. 关键绘图 API
    1)画线

    MoveToEx(hdc,x1,y1,NULL); //设置起点
    LineTo(hdc,x2,y2); //画到终点

    2)绘制矩形

    Rectangle(hdc, left, top, right, bottom);

    ● 边框:由当前 DC 的画笔控制
    ● 内部填充:由当前 DC 的画刷控制
    坐标原点 (0,0):绘图目标窗口左上角

    标准 GDI 绘图完整示例代码

    #include <windows.h>
    void DrawDemo(HWND hwnd)
    {
    //1.获取DC
    HDC hdc = GetDC(hwnd);
    //2.创建5像素红色实线画笔
    HPEN hPen = CreatePen(PS_SOLID,5,RGB(255,0,0));
    //3.获取系统可变色画刷
    HBRUSH hBrush = (HBRUSH)GetStockObject(DC_BRUSH);
    //4.把对象选入DC,保存旧对象!
    HGDIOBJ oldPen = SelectObject(hdc, hPen);
    HGDIOBJ oldBrush = SelectObject(hdc, hBrush);
    //修改画刷颜色为黄色
    SetDCBrushColor(hdc,RGB(255,255,0));
    //绘制400*400矩形
    Rectangle(hdc,0,0,400,400);
    //========资源恢复与释放【重中之重】========
    //恢复DC原来的对象
    SelectObject(hdc, oldPen);
    SelectObject(hdc, oldBrush);
    //销毁自定义GDI对象
    DeleteObject(hPen);
    //GetStockObject获取的对象可不删除
    //DeleteObject(hBrush);
    //释放设备上下文
    ReleaseDC(hwnd,hdc);
    }

    注意:直接在窗口外部调用绘图,窗口被遮挡、最小化再还原时,绘制内容会消失
    原因:窗口内容是实时绘制,窗口重绘消息WM_PAINT到来会刷新界面,真正绘图要写在 WM_PAINT 消息内部

    总结

  • 窗口本质:窗口没有永久保存图像,所有像素都是 GDI 实时绘制出来。窗口被遮挡后内容丢失,需要响应WM_PAINT重绘
  • HDC用完必须ReleaseDC;自己 Create 出来的 GDI 对象必须DeleteObject,否则 GDI 泄漏
  • SelectObject一定要保存旧对象,结束前还原回 DC,不能直接选入新对象不管
  • HWND全局有效;普通HANDLE只属于本进程
  • 画笔控制线条边框;画刷控制填充,画矩形、椭圆这类闭合图形两者同时生效
  • 赞(0)
    未经允许不得转载:171主机测评 » 窗口的本质
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址