Get HBITMAPs For *ALL* Sizes and Depths of a File Type Icon (C++)

Compiler: MinGW/GCC

I'm trying to get the HICON of a file type based on what icon windows has registered for that file type, and then grab all of the HICON's images.

The problem is, I can't seem to get anything other than the 32x32 or 16x16 icon. Also, I've looked at GetIconInfoEx() but that function doesn't allow me to choose the icon size that I'm wanting, it just sort of arbitrarily pukes up whatever Windows feels like handing me at the time.

I want to at least have all of the 16x16, 32x32, and 48x48 icons, but I would really enjoy being able to extract every size that's in the HICON that I pass in.

Here's the code I'm currently working with (copy and pasted most of this from the web and stitched it together):

HBITMAP GetFileTypeIcon(const char* ext, int type, int depth)
{
    HICON hIcon;
    SHFILEINFO sfi= {0};
    UINT flag = SHGFI_ICON|SHGFI_USEFILEATTRIBUTES;
    int wh = 16;
    switch(type)
    {
        default:
        case FILE_ICON_SIZE_16:
        {
            wh = 16; flag|=SHGFI_SMALLICON;
        }
        break;
        case FILE_ICON_SIZE_32:
        {
            wh = 32; flag|=SHGFI_LARGEICON; 
        }
        break;
        case FILE_ICON_SIZE_48:
        {
            wh = 48; flag|=SHGFI_SYSICONINDEX;
        }
        break;
        case FILE_ICON_SIZE_256:
        {
            wh = 256; flag|=SHGFI_SYSICONINDEX;
        }
        break;
    }
    HRESULT hr = SHGetFileInfo(ext,FILE_ATTRIBUTE_NORMAL,&sfi,sizeof(sfi),flag);
    if(SUCCEEDED(hr))
    {
        if((type == FILE_ICON_SIZE_48) || (type == FILE_ICON_SIZE_256))
        {
            // THIS PART DOESN'T COMPILE: undeclared function/indentifiers

            // HIMAGELIST* imageList;
            // hr = SHGetImageList(((type == FILE_ICON_SIZE_256)?SHIL_JUMBO:SHIL_EXTRALARGE), IID_IImageList, (void**)&imageList);
            // if(SUCCEEDED(hr))
            // {
            //     //Get the icon we need from the list. Note that the HIMAGELIST we retrieved
            //     //earlier needs to be casted to the IImageList interface before use.
            //     hr = ((IImageList*)imageList)->GetIcon(sfi.iIcon, ILD_TRANSPARENT, &hIcon);
            // }
        }
        else
        {
            hIcon=sfi.hIcon;
        }
    }

    // Convert to an HBITMAP (to get it out of the icon...)
    HDC hDC = GetDC(NULL);
    HDC hMemDC = CreateCompatibleDC(hDC);
    HBITMAP hMemBmp = CreateCompatibleBitmap(hDC, wh, wh);
    HGDIOBJ hOrgBMP = SelectObject(hMemDC, hMemBmp);

    DrawIconEx(hMemDC, 0, 0, hIcon, wh, wh, 0, NULL, DI_NORMAL);

    SelectObject(hMemDC, hOrgBMP);
    DeleteDC(hMemDC);
    ReleaseDC(NULL, hDC);
    DestroyIcon(hIcon);

    return hMemBmp;
}

I don't even know what to do about color depths. I'll hazard a guess: make a DC that has a certain color depth (rather than just a compatible DC) and pass that into DrawIconEx()?

Edit: I answered my own question after much research/work.

See my answer below for a way to find and parse the raw icon data.

Answers


Wow, talk about reinventing the wheel! With all due respect, this code is so bloated for nothing. I (and probably thousands of others) achieved the exact same result with 1/10 of this code. Also, this solution contains many inaccuracies.

Here's a quick run-down:

  1. Why parse the registry manually? You state the API has some problems; like what? I've used reg parsing API extensively and never had a problem! The Indexing vs ResID logic is correct though.

  2. Why do all the icon to bitmap conversions manually? This can be achieved with 3 to 5 lines of code using the right Icon API calls. Here's a complete reference.

  3. Why limit the conversion to 32bpp? Again, using the right APIs will generate a device dependent hIcon handle with the max color bit-depth supported by that device. Check out the CreateIconFromResourceEx() API function. All you need to do is combine it with the Find/Load/Lock Resource APIs that you're already using. Using this technique will load icons of any size and color depth (from monochrome up to alpha-channel 32bpp icons).

  4. Finally, regarding the search for icon resources by group (RT_GROUP_ICON), or by single icons (RT_ICON), and matching for a given index instead of resource, it could be done much more efficiently using EnumResourceNames(). It might be that you've failed to account for string resource identifiers when parsing the Enum return, because it seems you've omitted such case in your manual search and match procedure. This might be the source of your problems with EnumResourceNames(). It works perfectly fine for me and for others in countless online samples. At the very least, the "manual" search should match up to 0xFFFF rather than 0x8000. Res IDs are recommended in the 0x0001 to 0x8000 range, but legal in the 0x0000 to 0xFFFF range.


Need Your Help

c# draw a straight line

c# winforms line draw

How do i get a REAL straight line with c#? the code below draws a line, great, but this line is not perfect, it's not pixel by pixel straight, is there better code out there that produces a better,

rewrite rule php to non php not working

apache mod-rewrite url-rewriting rewrite

I have a read alot and this seems to be correct as to what i understand.

About UNIX Resources Network

Original, collect and organize Developers related documents, information and materials, contains jQuery, Html, CSS, MySQL, .NET, ASP.NET, SQL, objective-c, iPhone, Ruby on Rails, C, SQL Server, Ruby, Arrays, Regex, ASP.NET MVC, WPF, XML, Ajax, DataBase, and so on.