窗口的本质
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 | 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 消息内部





