CreateDIBSection返回NULL的原因排查求助
问题根源分析
导致CreateDIBSection返回NULL且GetLastError返回0的原因有以下几点:
- BITMAPINFO结构未正确初始化:代码修改了单独的
BITMAPINFOHEADER变量,但从未将修改后的内容复制回传入CreateDIBSection的BITMAPINFO结构中。原始BITMAPINFO处于未初始化状态(包含垃圾数据),导致函数接收到无效参数。 - biWidth值设置错误:
biWidth被设为每行的字节数(步长),而非实际的像素宽度(408)。BITMAPINFOHEADER.biWidth字段要求的是像素宽度,不是字节数。 - GetLastError调用时机错误:在调用
CreateDIBSection后,代码先调用了calloc、sprintf、MessageBox等函数,这些函数会覆盖系统的错误码,导致最终GetLastError返回0而非CreateDIBSection的实际错误。 - 未检查GetDC的返回值:
GetDC可能返回NULL,但代码未处理这种情况,会导致后续CreateDIBSection调用失败。
修正后的代码
TRESULT GetDIBPage(_IN HWND inobj, _INOUT void **outobj){ // Variable declarations void *tmpbits = NULL; char *tmpstr = NULL; BITMAPINFO tmpbmpinfo = {0}; // 初始化BITMAPINFO结构 HDC tmphdc = NULL; HWND tmphndwindow = NULL; int pixel_width = 408; // 实际像素宽度 int bytes_per_pixel = 3; // 24位色,每像素3字节 int stride = 0; DWORD last_err = 0; HBITMAP hbmp = NULL; // Argument checks if(inobj == NULL || outobj == NULL){ return TPTRISNULL; } // Initializations tmphndwindow = inobj; // 获取窗口设备上下文,并检查是否成功 tmphdc = GetDC(tmphndwindow); if(tmphdc == NULL){ MessageBox(NULL, "获取设备上下文失败", "错误", MB_OK); return TPTRISNULL; } // 计算步长(每行字节数,按4字节对齐) stride = pixel_width * bytes_per_pixel; if((stride % 4) != 0){ stride = (stride + 3) & ~3; // 向上取整到4的倍数 } // 设置BITMAPINFOHEADER字段 tmpbmpinfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); tmpbmpinfo.bmiHeader.biWidth = pixel_width; // 正确设置像素宽度 tmpbmpinfo.bmiHeader.biHeight = 600; tmpbmpinfo.bmiHeader.biPlanes = 1; tmpbmpinfo.bmiHeader.biBitCount = 24; tmpbmpinfo.bmiHeader.biCompression = BI_RGB; tmpbmpinfo.bmiHeader.biSizeImage = stride * 600; // 步长 × 高度 tmpbmpinfo.bmiHeader.biXPelsPerMeter = 0; tmpbmpinfo.bmiHeader.biYPelsPerMeter = 0; tmpbmpinfo.bmiHeader.biClrUsed = 0; tmpbmpinfo.bmiHeader.biClrImportant = 0; // 创建DIB Section,并立即获取错误码 hbmp = CreateDIBSection(tmphdc, &tmpbmpinfo, DIB_RGB_COLORS, &tmpbits, NULL, 0); last_err = GetLastError(); // 检查是否创建成功 if(hbmp == NULL || tmpbits == NULL){ tmpstr = (char*)calloc(513, sizeof(char)); if(tmpstr != NULL){ sprintf(tmpstr, "创建DIB失败。错误码:%lu", last_err); MessageBox(NULL, tmpstr, "错误", MB_OK); free(tmpstr); } ReleaseDC(tmphndwindow, tmphdc); return TPTRISNULL; } // 释放资源 ReleaseDC(tmphndwindow, tmphdc); // 返回结果 *outobj = tmpbits; return TSUCCESS; }
关键修正点说明
- 正确初始化BITMAPINFO:使用
={0}初始化BITMAPINFO结构,确保所有字段初始为0,然后直接设置bmiHeader的各个有效值,避免垃圾数据传入函数。 - 区分像素宽度和步长:将
biWidth设为实际像素宽度408,单独计算步长(每行字节数)用于biSizeImage。 - 及时获取错误码:在
CreateDIBSection调用后立即获取GetLastError,避免后续函数覆盖错误码。 - 增加GetDC错误检查:判断
GetDC的返回值,若为NULL则直接返回错误。 - 检查CreateDIBSection的返回值:通过返回的
HBITMAP句柄和tmpbits双重验证创建是否成功。
内容的提问来源于stack exchange,提问作者Thema Guishard
相关产品推荐
相关产品推荐

