7

How to convert HICON to HBITMAP in VC++?

I know this is an FAQ but all the solutions I've found on Google don't work. What I need is a function which takes a parameter HICON and returns HBITMAP.

Greatest if possible to make conversion to 32-bit bitmap even the icon is 24-bit, 16-bit or 8-bit.

This is the code, I don't know where it goes wrong:

HBITMAP icon_to_bitmap(HICON Icon_Handle) {
  HDC Screen_Handle = GetDC(NULL);
  HDC Device_Handle = CreateCompatibleDC(Screen_Handle);

  HBITMAP Bitmap_Handle = 
  CreateCompatibleBitmap(Device_Handle,GetSystemMetrics(SM_CXICON),
  GetSystemMetrics(SM_CYICON));

  HBITMAP Old_Bitmap = (HBITMAP)SelectObject(Device_Handle,Bitmap_Handle);
  DrawIcon(Device_Handle, 0,0, Icon_Handle);
  SelectObject(Device_Handle,Old_Bitmap);

  DeleteDC(Device_Handle);
  ReleaseDC(NULL,Screen_Handle);
  return Bitmap_Handle;
}
jondinham
  • 8,271
  • 17
  • 80
  • 137

4 Answers4

8

this code do it:

HICON hIcon = (HICON)LoadImage(instance, MAKEINTRESOURCEW(IDI_ICON), IMAGE_ICON, width, height, 0);
ICONINFO iconinfo;
GetIconInfo(hIcon, &iconinfo);
HBITMAP hBitmap = iconinfo.hbmColor;

and this is the code in the *.rc file:

IDI_ICON ICON "example.ico"

and this is the code in the *.h file:

#define IDI_ICON 4000
user1544067
  • 1,676
  • 2
  • 19
  • 30
  • Can you elaborate on this solution? Is `hbmColor` sufficient to represent an icon in HBITMAP? What about the `hbmMask` ? – hackjutsu Aug 15 '17 at 23:07
7
HDC hDC = GetDC(NULL);
HDC hMemDC = CreateCompatibleDC(hDC);
HBITMAP hMemBmp = CreateCompatibleBitmap(hDC, x, y);
HBITMAP hResultBmp = NULL;
HGDIOBJ hOrgBMP = SelectObject(hMemDC, hMemBmp);

DrawIconEx(hMemDC, 0, 0, hIcon, x, y, 0, NULL, DI_NORMAL);

hResultBmp = hMemBmp;
hMemBmp = NULL;

SelectObject(hMemDC, hOrgBMP);
DeleteDC(hMemDC);
ReleaseDC(NULL, hDC);
DestroyIcon(hIcon);
return hResultBmp;
Euan
  • 71
  • 1
  • 2
3

I don't have code readily available to share, but I think this is pretty easy. You have to create the HBITMAP, create a device context, select the bitmap into the DC (this will make the bitmap the drawing area for this DC). Finally call the DrawIcon() function to draw your icon on this DC. After that detach the bitmap from the DC and destroy the DC. Your bitmap now should be ready to go.

Update after looking at your code:

I believe the problem is in the createCompatibleBitmap call. You are asking for a bitmap compatible with the memory DC, but memory DCs start with a 1 bit/pixel bitmap selected into them. Try asking for a bitmap compatible with the screen DC instead.

Update 2: you may want to look at this question as it seems related to your problem.

Community
  • 1
  • 1
Miguel Grinberg
  • 65,299
  • 14
  • 133
  • 152
  • i'm doing the same thing but the resulting bitmap is always 1bit/pixel. so strange....... – jondinham Sep 10 '11 at 22:15
  • 1
    Please expand your question with sample code. Sounds like your bitmap was not created with the right bits/pixel, but can't say for sure without looking at the code. – Miguel Grinberg Sep 10 '11 at 22:16
  • added the code, the DC created from screen so it's supposed to be 32bit/pixel, pls have a look.... – jondinham Sep 10 '11 at 22:24
  • 1
    I have updated my answer, give that a try and let me know if it helps! – Miguel Grinberg Sep 10 '11 at 23:03
  • i find it out now that it doesn't seem because of the function i wrote, because of the pass-in param 'Icon_Handle'; i don't know why it's always NULL, this Icon_Handle is gotten from SendMessage(...,WM_GETICON,...); strangely that SendMessage doesn't return the pointer to icon – jondinham Sep 10 '11 at 23:07
  • 1
    See the link I've added to the question, it may be of help. – Miguel Grinberg Sep 10 '11 at 23:20
2

I found this(similar code works for me - 32x32 icons with or without alpha data):
  used CopyImage (msdn link)

HICON hICON = /*your code here*/
HBITMAP hBITMAPcopy;
ICONINFOEX IconInfo;
BITMAP BM_32_bit_color;
BITMAP BM_1_bit_mask;

// 1. From HICON to HBITMAP for color and mask separately
//.cbSize required
//memset((void*)&IconInfo, 0, sizeof(ICONINFOEX));
IconInfo.cbSize = sizeof(ICONINFOEX);
GetIconInfoEx( hICON , &IconInfo);


//HBITMAP IconInfo.hbmColor is 32bit per pxl, however alpha bytes can be zeroed or can be not.
//HBITMAP IconInfo.hbmMask is 1bit per pxl

// 2. From HBITMAP to BITMAP for color
//    (HBITMAP without raw data -> HBITMAP with raw data)
//         LR_CREATEDIBSECTION - DIB section will be created,
//         so .bmBits pointer will not be null
hBITMAPcopy = (HBITMAP)CopyImage(IconInfo.hbmColor, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION);
//    (HBITMAP to BITMAP)
GetObject(hBITMAPcopy, sizeof(BITMAP), &BM_32_bit_color);
//Now: BM_32_bit_color.bmBits pointing to BGRA data.(.bmWidth * .bmHeight * (.bmBitsPixel/8))

// 3. From HBITMAP to BITMAP for mask
hBITMAPcopy = (HBITMAP)CopyImage(IconInfo.hbmMask, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION);
GetObject(hBITMAPcopy, sizeof(BITMAP), &BM_1_bit_mask);
//Now: BM_1_bit_mask.bmBits pointing to mask data (.bmWidth * .bmHeight Bits!)

BM_32_bit_color bitmap may be have Alpha *channel*(each 4th byte) already set! So - check for it before u add mask bit to color data.

befzz
  • 1,232
  • 13
  • 11