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

使用GetObject加载位图失败,自绘按钮无法正常显示位图

问题分析与解决方案

核心问题:位图资源加载逻辑错误

你当前代码把LoadResource返回的HGLOBAL直接当成HBITMAP使用,这是完全错误的——LoadResource仅负责将资源加载到内存,返回的是内存块句柄,并非GDI位图句柄,这直接导致GetObject、DrawStateW等GDI函数无法正常工作。

同时资源释放也存在错误:HRSRC不是GDI对象,不能用DeleteObject释放;LoadResource返回的HGLOBAL需要用FreeResource释放,但如果用正确的位图加载函数,这些手动释放步骤可以省略。

修正后的代码

void on_WM_DRAWITEM(DRAWITEMSTRUCT* drawItem, HWND hwnd)
{
    // 直接用LoadBitmapW加载资源位图,返回合法的HBITMAP句柄
    HBITMAP hBm = LoadBitmapW(GetModuleHandleW(NULL), MAKEINTRESOURCEW(MY_BITMAP));
    BITMAP bm;
    HDC memDC = CreateCompatibleDC(drawItem->hDC);

    if (hBm != NULL && memDC != NULL)
    {
        printf("HBITMAP: %p\n", hBm);
        printf("HDC: %p\n", memDC);

        if (GetObjectW(hBm, sizeof(bm), &bm) != 0)
        {
            printf("BITMAP width: %d, height: %d\n", bm.bmWidth, bm.bmHeight);
            // 将位图选入内存DC
            HBITMAP oldBm = (HBITMAP)SelectObject(memDC, hBm);
            // 绘制位图到按钮DC
            BitBlt(drawItem->hDC, 0, 0, bm.bmWidth, bm.bmHeight, memDC, 0, 0, SRCCOPY);
            // 恢复内存DC原来的位图
            SelectObject(memDC, oldBm);
        }

        printf("BITMAP: %p\n", &bm);
        printf("BITMAP BITS: %p\n", bm.bmBits);
    }

    // 正确释放资源
    if (memDC != NULL) DeleteDC(memDC);
    if (hBm != NULL) DeleteObject(hBm);
}

关键修正点说明

  • 用LoadBitmapW加载位图资源:这个函数专门处理位图资源,会自动完成FindResource、LoadResource、LockResource的流程,直接返回可用的HBITMAP句柄。
  • 位图选入内存DC:必须使用SelectObject将位图绑定到内存DC后,才能通过BitBlt完成绘制,你之前的代码跳过了这一步,导致绘制无效。
  • 正确释放资源:HBITMAP是GDI对象,用DeleteObject释放;内存DC用DeleteDC释放;HRSRC和HGLOBAL的手动处理全部省略,由LoadBitmapW内部完成。

关于句柄与指针的说明

  • Windows句柄是内核对象的标识(可以是指针或索引值),用%p打印是没问题的,但它不是用户空间的直接内存指针,不能直接解引用访问内存(比如你之前看到的bm.bmBits是无效值,因为当时的hBm不是真正的HBITMAP)。只有当函数明确返回用户空间指针时(比如LockResource),才能直接访问对应的内存。

内容的提问来源于stack exchange,提问作者Etienne Poulin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 07:51:11