Link to home
Start Free TrialLog in
Avatar of PinTail
PinTailFlag for United Kingdom of Great Britain and Northern Ireland

asked on

How to save an Icon to file from an HICON

I thought this would be pretty simple, but it turns out to be quite complicated.

The problem in more detail is this.

Assume that you have only an HICON (which was passed to your function) and wish to write an .ico file (file containing an ICON resource formatted according to the spec)

I am having terrible trouble getting enough information about the Icon to be able to populate the appropriate structures embedded in the resource.


Particularly I have been unable to get GetDIBits to return sensible data

here is a relevant code snippet.


Func( HICON hIconLarge, hIconSmall)
{
ICONINFO iiLarge, iiSmall;

CBitmap oBMLargeColor, oBMLargeMask, oBMSmallColor, oBMSmallMask;
BITMAP bmLargeColor, bmLargeMask, bmSmallColor, bmSmallMask;
BITMAPINFO bmiLargeColor, bmiLargeMask, bmiSmallColor, bmiSmallMask;


// If lpvBits is NULL, GetDIBits examines the first member of the first structure pointed to by lpbi.
// This member must specify the size, in bytes, of a BITMAPCOREHEADER or a BITMAPINFOHEADER structure.
// The function uses the specified size to determine how the remaining members should be initialized.

// If lpvBits is NULL and the bit count member of BITMAPINFO is initialized to zero,
// GetDIBits fills in a BITMAPINFOHEADER structure or BITMAPCOREHEADER without the color table.
// This technique can be used to query bitmap attributes.


// we want a BITMAPINFOHEADER type
bmiLargeColor.bmiHeader.biSize = bmiLargeMask.bmiHeader.biSize = \
bmiSmallColor.bmiHeader.biSize = bmiSmallMask.bmiHeader.biSize = sizeof(BITMAPV4HEADER);

// we want the color table
bmiLargeColor.bmiHeader.biBitCount = bmiLargeMask.bmiHeader.biBitCount = \
bmiSmallColor.bmiHeader.biBitCount = bmiSmallMask.bmiHeader.biBitCount = 1;



     
     GetIconInfo(hIconLarge, &iiLarge);
     GetIconInfo(hIconSmall, &iiSmall);


     oBMLargeColor.Attach(iiLarge.hbmColor);
     oBMLargeMask.Attach(iiLarge.hbmMask);
     oBMSmallColor.Attach(iiSmall.hbmColor);
     oBMSmallMask.Attach(iiSmall.hbmMask);

     oBMLargeColor.GetBitmap(&bmLargeColor);
     oBMLargeMask.GetBitmap(&bmLargeMask);
     oBMSmallColor.GetBitmap(&bmSmallColor);
     oBMSmallMask.GetBitmap(&bmSmallMask);


     CDC* pDC = GetWindowDC();
     HDC hDC = pDC->m_hDC;
     if( 0 == GetDIBits(hDC, iiLarge.hbmColor, bmLargeColor.bmHeight-1, 0, NULL, &bmiLargeColor, DIB_RGB_COLORS) )
          ShowLastError();
     GetDIBits(hDC, iiLarge.hbmMask, bmLargeMask.bmHeight-1, 0, NULL, &bmiLargeMask, DIB_RGB_COLORS);
     GetDIBits(hDC, iiSmall.hbmColor, bmSmallColor.bmHeight-1, 0, NULL, &bmiSmallColor, DIB_RGB_COLORS);
     GetDIBits(hDC, iiSmall.hbmMask, bmSmallMask.bmHeight-1, 0, NULL, &bmiSmallMask, DIB_RGB_COLORS);



     ReleaseDC(pDC);
     oBMLargeColor.Detach();
     oBMLargeMask.Detach();
     oBMSmallColor.Detach();
     oBMSmallMask.Detach();

     DeleteObject(iiLarge.hbmColor);
     DeleteObject(iiLarge.hbmMask);
     DeleteObject(iiSmall.hbmColor);
     DeleteObject(iiSmall.hbmMask);

}
Avatar of PinTail
PinTail
Flag of United Kingdom of Great Britain and Northern Ireland image

ASKER

OK, after lots of digging around I have discovered htta unless the BITMAPINFO structure passed to GetDIBits is zero's out before the call,it returns a load of garbage.

It is unclear why this would be the case.  I was setting the appropriate members, and assuming the rest would be filled in.  actually I have to comment this line to get it to work
     // we want the color table
//     bmiLargeColor.bmiHeader.biBitCount = bmiLargeMask.bmiHeader.biBitCount = \
//          bmiSmallColor.bmiHeader.biBitCount = bmiSmallMask.bmiHeader.biBitCount = 1;


Now, I still need to understand how to get at the color table, if any, and then propulate the three Icon resource structures as defined in this article
\MSDN\2001JUL\1033\techart.chm::/html/msdn_icons.htm

The GetDIBits function seems very flakey, but looks like it should provide me with the color information required, I can see that I will be playing around with it a bit more.

ANy help in advance would be appreciated
Avatar of jkr
There seems to be an easier method - see http://support.microsoft.com/support/kb/articles/Q104/5/70.asp
Avatar of PinTail

ASKER

Yes, I saw that, doesn't seem to work.
GlobalSize always returns 0 (zero)
and GlobalLock fails to return a valid pointer.

I can only imagine that the person that wrote that article had never actually tried to implement the code; either that or it only works when the Icon is loaded via the method described.

Since I have no control over how the Icon is being loaded - I only get passed an HICON - I cannot use this method.

Any other help ??
Avatar of Madshi
Madshi

I think you have to fill the BITMAPINFO structure you give in to GetDIBits, because GetDIBits tries to return whatever you want to have. And what you want to have, you define by filling the BITMAPINFO structure. Just settings it zero is not right, I think. You should call GetObject for the 2 bitmaps you get from GetIconInfo. GetObject will tell you want you have to fill into the BITMAPINFO structure. Only if you do that, GetDIBits will return the color values to you. At least I understand the documentation this way...

Regards, Madshi.
PinTail:

Please provide feedback in your open questions.

thanks!
amp
community support moderator
ASKER CERTIFIED SOLUTION
Avatar of modulo
modulo

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial