使用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
相关产品推荐
相关产品推荐

