使用GetDIBits捕获屏幕/窗口区域时无输出的问题排查
问题修复方案
核心问题排查与修复
1. 修正BitmapInfo的size字段赋值
BITMAPINFOHEADER的biSize固定为40(对应原生结构的字节大小),请确保该字段赋值正确,替换代码中的biSize变量为固定值:
info.header.size = 40;
2. 为GetDIBits的DllImport添加输出标记
.NET默认不会将数组自动识别为输出参数,需在DllImport中显式添加[Out]属性,确保数据能正确写入数组:
[DllImport("gdi32")] public static extern int GetDIBits(IntPtr context, IntPtr bitmap, uint start, uint lines, [Out] RGBQuad[] bits, ref BitmapInfo header, uint usage);
3. 校验RGBQuad结构定义
确保你的RGBQuad与Win32原生结构完全匹配,正确定义如下:
[StructLayout(LayoutKind.Sequential)] public struct RGBQuad { public byte rgbBlue; public byte rgbGreen; public byte rgbRed; public byte rgbReserved; }
4. 规范GDI资源管理
调用SelectObject后保存旧对象并最终恢复,避免资源泄漏和上下文异常:
var oldBitmap = SelectObject(newDC, map); // 中间业务代码 SelectObject(newDC, oldBitmap); // 恢复原DC对象 DeleteObject(map); DeleteDC(newDC);
5. 添加错误检查
通过GetDIBits的返回值和GetLastError排查执行失败原因:
int result = GetDIBits(newDC, map, 0, height, pixels, ref info, 0); if (result == 0) { int errorCode = Marshal.GetLastWin32Error(); throw new System.ComponentModel.Win32Exception(errorCode); }
完整修复后的核心代码
public RGBQuad[] GetBitmap(int x, int y, uint width, uint height) { var newDC = CreateCompatibleDC(context); var map = CreateCompatibleBitmap(context, width, height); var oldBitmap = SelectObject(newDC, map); var info = new BitmapInfo(); info.header.bitCount = 32; info.header.compression = 0; // BI_RGB info.header.planes = 1; info.header.width = (int)width; // 匹配原生结构的int类型 info.header.height = -(int)height; // 负数表示正向像素顺序,避免翻转 info.header.size = 40; // 固定为BITMAPINFOHEADER的字节大小 info.header.sizeImage = width * height * 4; // 显式指定32位图像的总字节数 var pixels = new RGBQuad[width * height]; BitBlt(newDC, 0, 0, width, height, context, x, y, 13369376 /*SRCCOPY*/); int result = GetDIBits(newDC, map, 0, height, pixels, ref info, 0 /*DIB_RGB_COLORS*/); if (result == 0) { throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error()); } SelectObject(newDC, oldBitmap); DeleteObject(map); DeleteDC(newDC); return pixels; }
额外说明
- 将
height设为负数,可让GetDIBits返回从上到下的正向像素顺序,无需后续翻转数组。 - 显式设置
sizeImage能帮助GDI精准计算缓冲区大小,降低读取失败概率。
内容的提问来源于stack exchange,提问作者Aidan Reid
相关产品推荐
相关产品推荐

