You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 16:55:43