BMP图片查看器内存释放失败求助:无法释放内存DC及相关内存
BMP图片查看器内存释放失败问题排查与修复
核心错误点分析
1. DC释放方式完全错误
memDC是通过CreateCompatibleDC创建的设备上下文,必须用DeleteDC释放,ReleaseDC仅适用于释放GetDC/GetWindowDC获取的DC,你调用ReleaseDC(hWnd, memDC)必然触发“Invalid DC”错误。- 错误调用
DeleteObject(memDC):DC不属于GDI对象(位图、画笔这类才是),不能用DeleteObject销毁,这会导致后续DC资源管理彻底混乱。
2. data内存管理冲突
- 你先通过
malloc(dataSize)分配了data,但CreateDIBSection会重新分配一块内存并覆盖data指针:原malloc的内存地址直接丢失,造成泄漏;而现在的data是系统分配的内存,根本不能用free释放,这就是free(data)抛出异常的根源。 CreateDIBSection分配的内存与返回的HBITMAP句柄绑定,只需调用DeleteObject(hBit)就能自动释放这块内存,无需手动操作data。
3. 未恢复DC中的原始位图
调用SelectObject(memDC, hBit)替换DC中的位图后,没有将DC原来的占位位图恢复回去,会导致DeleteDC无法正确销毁memDC,引发资源泄漏。
4. Static变量未初始化
hBit、memDC、winDC都是static变量,首次运行时没有初始化,当data != NULL进入释放分支时,这些变量可能是无效的随机值,导致DeleteObject(hBit)等操作提前出错。
修正后的关键代码片段
static BYTE *data = NULL; static HDC memDC = NULL; static HDC winDC = NULL; static HBITMAP hBit = NULL; static HBITMAP hOldBit = NULL; // 保存DC原始占位位图 HANDLE hFile; if (data != NULL) { // 恢复DC原始位图,否则无法正常销毁DC if (hOldBit != NULL) { SelectObject(memDC, hOldBit); hOldBit = NULL; } // 释放DIBSection关联的内存(自动释放data指向的系统内存) if (hBit != NULL) { DeleteObject(hBit); hBit = NULL; } // 销毁CreateCompatibleDC创建的DC if (memDC != NULL) { DeleteDC(memDC); memDC = NULL; } // 释放GetDC获取的窗口DC if (winDC != NULL) { ReleaseDC(hWnd, winDC); winDC = NULL; } data = NULL; } szFile = OpenBmp(hWnd); if (szFile != NULL) { // wcscpy_s第二个参数是缓冲区总大小(宽字符单位),避免溢出 wcscpy_s(fName, sizeof(fName)/sizeof(fName[0]), szFile); } else { return NULL; } hFile = CreateFile(fName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) { CloseHandle(hFile); return NULL; } BITMAPFILEHEADER bfh; BITMAPINFOHEADER fif; DWORD num; BOOL R = ReadFile(hFile, &bfh, sizeof(BITMAPFILEHEADER), &num, NULL); if (R && num == sizeof(BITMAPFILEHEADER)) { R = ReadFile(hFile, &fif, sizeof(BITMAPINFOHEADER), &num, NULL); if (R && num == sizeof(BITMAPINFOHEADER)) { winDC = GetDC(hWnd); memDC = CreateCompatibleDC(winDC); GetClientRect(hWnd, &rect); BITMAPINFO pbmi = {0}; pbmi.bmiHeader = fif; width = fif.biWidth; height = fif.biHeight; // 直接让CreateDIBSection分配内存,无需提前malloc hBit = CreateDIBSection(memDC, &pbmi, DIB_RGB_COLORS, (void**)&data, NULL, 0); if (hBit != NULL) { // 保存DC原始位图,后续需要恢复 hOldBit = (HBITMAP)SelectObject(memDC, hBit); // 读取位图数据到系统分配的内存中 R = ReadFile(hFile, data, bfh.bfSize - bfh.bfOffBits, &num, NULL); open = TRUE; InvalidateRect(hWnd, &rect, TRUE); } } } CloseHandle(hFile);
额外注意事项
- 所有API调用必须检查返回值(比如
CreateFile是否返回INVALID_HANDLE_VALUE),及时处理错误分支。 - 避免手动malloc与
CreateDIBSection的内存分配冲突,直接让系统管理DIBSection的内存。
内容的提问来源于stack exchange,提问作者helong jin
相关产品推荐
相关产品推荐

