Question

I'm loading an ICON of another application via

HICON ico = ExtractIcon(NULL, L"path\\to\\OtherApp.exe", 0);

How can I create a CBitmap object from this icon?

Specifically (not really answered in the dup question for me):

  • Which device context?
  • At the end, I want a CBitmap object that outlives the function that converts the icon:
  • What do I need to clean up immediately and what do I need to keep around? (DC, ...?)

Here's the code I have so far:

void ConvertIconToBitmap(CBitmap& bmpObj, HICON hIcon, int cx, int cy) {
    CClientDC clientDC(NULL);
    CDC dc;
    dc.CreateCompatibleDC(NULL);

    CBitmap bmpTmp;
    VERIFY( bmpTmp.CreateCompatibleBitmap(&clientDC, cx, cy) );
    CBitmap* pOldBmp = (CBitmap*)dc.SelectObject(&bmpTmp);
    VERIFY( ::DrawIconEx( dc.GetSafeHdc(), 0, 0, hIcon, cx, cy, 0, NULL, DI_NORMAL) );
    dc.SelectObject( pOldBmp );

    // For some reason I need to copy the bitmap here: (maybe it's the DIB flag)
    HBITMAP hDibBmp = (HBITMAP)::CopyImage((HANDLE)(HBITMAP)bmpTmp, IMAGE_BITMAP, 0, 0, LR_DEFAULTSIZE | LR_CREATEDIBSECTION);
    VERIFY( hDibBmp );
    VERIFY( bmpObj.Attach(hDibBmp) );
    // VERIFY( bmpObj.Attach(bmpTmp.Detach()) );
}

Now, this code works, but I don't understand it:

  • Why do I need a CClientDC? (If I use only CDC the bitmap is not shown or Black&White, depending on where I put it.)
  • (Why) is the dc.SelectObject( pOldBmp ) line needed?
  • Why do I have to do CopyImage? (If I don't, the bitmap is sometimes drawn with inverted colors.)
  • Does this code leak anything or is everything properly cleaned up?

Here's another version that also seems to work:

void ConvertIconToBitmap2(CBitmap& bmpObj, HICON hIcon, int cx, int cy) {
    CClientDC clientDC(NULL);
    CDC memDC;
    memDC.CreateCompatibleDC(&clientDC);

    ASSERT(hIcon);
    ICONINFO info;
    VERIFY(GetIconInfo(hIcon, &info));
    BITMAP bmp;
    GetObject(info.hbmColor, sizeof(bmp), &bmp);
    HBITMAP hBitmap = (HBITMAP)CopyImage(info.hbmColor, IMAGE_BITMAP, 0, 0, 0);
    ASSERT(hBitmap);
    ASSERT(memDC.GetSafeHdc());
    HBITMAP hOldBmp = (HBITMAP)memDC.SelectObject(hBitmap);
    clientDC.BitBlt(0, 0, bmp.bmWidth, bmp.bmHeight, &memDC, 0, 0, SRCCOPY);
    memDC.SelectObject(hOldBmp);

    VERIFY( bmpObj.Attach(hBitmap) );
    DeleteObject(info.hbmColor);
    DeleteObject(info.hbmMask);
}
Was it helpful?

Solution

•Why do I need a CClientDC? (If I use only CDC the bitmap is not shown or Black&White, depending on where I put it.)

You would need a DC that is based on your window or the screen, just declaring a CDC is not enough, you will also need to call dc.Attach() or one of the CDC::Create* functions.

•(Why) is the dc.SelectObject( pOldBmp ) line needed?

So that the bitmap is disconnected from the DC

•Why do I have to do CopyImage? (If I don't, the bitmap is sometimes drawn with inverted colors.)

It looks like you are creating a device independent bimap using the CopyImage() call using the LR_CREATEDIBSECTION parameter

•Does this code leak anything or is everything properly cleaned up?

Looks ok to me!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top