windows gdi截屏需用getdc(null)获取全屏dc并及时releasedc,创建兼容位图须用该dc,保存bmp需严格按规范构造文件头、信息头及bgr对齐像素数据,注意biheight符号与字节对齐。

Windows平台用GDI截屏必须先获取屏幕设备上下文
直接调用 GetDC(NULL) 获取全屏设备上下文(DC)是前提,不能传窗口句柄或用 GetWindowDC,否则可能只截到桌面窗口区域或黑屏。注意这个 DC 是只读的,且必须在使用后立即用 ReleaseDC(NULL, hdc) 释放,否则长期持有会导致 GDI 句柄泄漏。
常见错误现象:BitBlt 返回 0、截图全黑、部分区域缺失——大概率是 DC 获取失败或未正确选入兼容位图。
- 确保在 GUI 线程中调用,控制台程序需链接
user32.lib并隐式初始化 GDI - 不要用
CreateCompatibleDC(NULL)后再试图从 NULL 获取位图,必须用CreateCompatibleBitmap(hdc, width, height) - 截取分辨率超过 32767×32767 的多屏组合时,
GetSystemMetrics(SM_CXSCREEN)会截断,应改用GetSystemMetrics(SM_CXVIRTUALSCREEN)和GetSystemMetrics(SM_XVIRTUALSCREEN)
保存为BMP需手动构造文件头和信息头
BMP 是裸格式,C++ 标准库不提供直接写入支持,必须按规范填充 BITMAPFILEHEADER 和 BITMAPINFOHEADER,再把像素数据按 BGR 顺序(不是 RGB)、每行字节对齐到 4 字节写入文件。Windows GDI 的 GetDIBits 可以帮你提取像素,但要求目标缓冲区足够大且格式匹配。
容易踩的坑:biSizeImage 字段不能设为 0(除非用 BI_RGB 且无压缩),否则某些图像查看器打不开;bfOffBits 必须等于文件头 + 信息头 + 调色板长度(真彩色无调色板,即 54 字节)。
- 调用
GetDIBits(hdcMem, hbm, 0, height, bits, &bi, DIB_RGB_COLORS)前,bi.biHeight应为负值(顶向下位图),否则像素会垂直翻转 - 申请像素缓冲时,按
((width * 3 + 3) & ~3) * height计算实际大小(3 字节/BGR,4 字节对齐) - 写文件必须用二进制模式:
fopen("screen.bmp", "wb"),文本模式会损坏二进制数据
跨编译器要注意结构体字节对齐
BITMAPFILEHEADER 和 BITMAPINFOHEADER 是 Windows SDK 定义的紧凑结构体,默认按 2 字节对齐。如果项目开启了 #pragma pack(1) 或使用 clang/gcc 的 -fpack-struct,可能导致结构体尺寸变小、字段错位,最终生成无效 BMP。
典型表现:生成的 BMP 文件头前两个字节不是 "BM",或者用 file 命令查看显示 “data” 而非 “BMP”。
- 显式加
#pragma pack(push, 2)包裹头定义,用完恢复:#pragma pack(pop) - 或直接用
sizeof(BITMAPFILEHEADER) == 14 && sizeof(BITMAPINFOHEADER) == 40断言校验 - 不要手写结构体字段顺序,始终
#include <windows.h></windows.h>并用 SDK 原生定义
完整流程里最容易被忽略的是像素数据翻转和 Alpha 通道处理
GDI 截屏默认不带 Alpha,但如果你用了 PrintWindow 或 layered window,可能混入透明像素;而 BMP v3 不支持 Alpha,强行写入会破坏格式。更隐蔽的问题是:多数显示器是“顶向下”坐标系,但 GDI 的兼容位图默认是“底向上”,GetDIBits 写出的数据行序是反的——你看到的图片上下颠倒,就是没处理好 bi.biHeight 符号或没传 DIB_RGB_COLORS。
- 安全做法:设
bi.biHeight = -height,这样GetDIBits输出的就是顶向下顺序,与文件格式一致 - 如果必须用正 height,则需手动将像素缓冲逐行倒序拷贝
- 完全避免 Alpha:创建兼容位图时用
RGB(0,0,0)初始化背景,或截屏后用SetBkColor/SetTextColor清除潜在混合影响
真正跑通的关键不在代码长短,而在是否严格匹配 BMP 文件规范的字节布局和 GDI 的位图方向约定。哪怕一个字节偏移错了,结果就是无法打开——这种问题没法靠日志定位,只能靠 hex editor 对比标准 BMP 结构。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











