1

编译器: MinGW/GCC

我正在尝试根据已为该文件类型注册的图标窗口来获取文件类型的 HICON,然后获取所有 HICON 的图像。

问题是,除了 32x32 或 16x16 图标之外,我似乎什么也得不到。此外,我已经看过GetIconInfoEx()但该功能不允许我选择我想要的图标大小,它只是随意地吐出任何 Windows 感觉当时给我的感觉。

我希望至少拥有所有 16x16、32x32 和 48x48 图标,但我真的很喜欢能够提取我传入的 HICON 中的每个尺寸。

这是我目前正在使用的代码(从网上复制并粘贴大部分内容并将其拼接在一起):

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;
}

我什至不知道如何处理颜色深度。我会冒险猜测:制作一个具有一定颜色深度的 DC(而不仅仅是兼容的 DC)并将其传递给DrawIconEx()?

编辑:经过大量研究/工作,我回答了自己的问题。

有关查找和解析原始图标数据的方法,请参阅下面的答案。

4

3 回答 3

1

哇,谈论重新发明轮子!恕我直言,这段代码太臃肿了。我(可能还有成千上万的其他人)用这段代码的 1/10 实现了完全相同的结果。此外,该解决方案包含许多不准确之处。

这是一个快速的总结:

  1. 为什么要手动解析注册表?您说 API 存在一些问题;像什么?我已经广泛使用了 reg 解析 API,从来没有遇到过问题!Indexing vs ResID 逻辑是正确的。

  2. 为什么所有的图标到位图的转换都是手动的?这可以通过 3 到 5 行代码使用正确的图标 API 调用来实现。这是一个完整的参考

  3. 为什么将转换限制为 32bpp?同样,使用正确的 API 将生成一个设备相关的 hIcon 句柄,该句柄具有该设备支持的最大颜色位深度。查看CreateIconFromResourceEx()API 函数。您需要做的就是将它与Find/Load/Lock Resource您已经在使用的 API 结合起来。使用此技术将加载任何大小和颜色深度的图标(从单色到 alpha 通道 32bpp 图标)。

  4. RT_GROUP_ICON最后,关于按组( )或单个图标( )搜索图标资源RT_ICON,并匹配给定索引而不是资源,使用EnumResourceNames(). 可能是您在解析 Enum 返回时未能考虑字符串资源标识符,因为您似乎在手动搜索和匹配过程中省略了这种情况。这可能是您的问题的根源EnumResourceNames()。在无数在线示例中,它对我和其他人都非常有效。至少,“手动”搜索应该匹配到 0xFFFF 而不是 0x8000。建议在 0x0001 到 0x8000 范围内使用 Res ID,但在 0x0000 到 0xFFFF 范围内是合法的

于 2013-07-22T13:44:11.303 回答
1

我基本上必须自己做所有事情(在网络、Stack Overflow 和几篇 MSDN 文章的帮助下),所以我想我会在这里发布我自己的解决方案。

我最终解析了注册表以找到每个先前注册的文件扩展名的图标的位置,因为应该可以轻松获得我想要的信息的 API 函数有一些......问题。

之后,我花了几天时间通过观察图标程序的输出来手动观察手头的数据格式,并且有了这些信息,我能够构建一个图像加载器。

我使用 Allegro 游戏库来更轻松地处理 BITMAP 图像 - Win32/GDI 有点难以处理,并且会使代码变得非常混乱。


查找图标位置和索引:

(1)在 HKEY_CLASSES_ROOT 下寻找扩展名,例如HKCR\.foo\(default) = "foofile"

(2) this 的默认数据是下一个要查看的关键,例如HKCR\foofile\

(3)这里的默认数据是描述 egHKCR\foofile\(default) = "Foo Document"

(4)图标位置可能在我知道的两个地方之一:

在里面HKCR\foofile\DefaultIcon\(default) 可能有一个类似的条目HKCR\foofile\CurVer\(default) = "foofile.1",告诉您查看HKCR\foofile.1\DefaultIcon\(default)图标位置的键。

解析图标位置字符串:

该字符串只是一个路径,后跟一个逗号、空格、可能是一个负号和一个指示图标“索引”的数字。

这是一个大问题:让图标索引为 N。如果 N 为负数(可能要检查负零!),它是指定文件中的资源 ID 。如果 N 为正,则表示在文件中找到第N个图标,但该图标不一定在资源 ID 号 N。


手动解析图标结构:

这是大部分代码和花费的时间,但它工作得很好。首先,这里是颜色和蒙版数据各个部分的数据格式。

数据块格式:

32bit ... Color Data:
====================================================================================
Little Endian 4 byte ARGB values.
The rows are stored in reverse order (bottom to top).


24bit ... Color Data:
====================================================================================
Little Endian 3 byte RGB values.
Tightly Packed (NO PADDING).
INSERT PADDING BYTES TO GO UP TO NEXT DWORD AT END OF ROW. SET THEM TO 0x00.
The rows are stored in reverse order (bottom to top).


16bit ... Color Data:
====================================================================================
Little Endian 2 byte RGB values. 5 bits each with MSB = 0.
Tightly Packed (NO PADDING).
INSERT PADDING BYTES TO GO UP TO NEXT DWORD AT END OF ROW. SET THEM TO 0x00.
The rows are stored in reverse order (bottom to top).


8bit ... Palette & Color Data:
====================================================================================
The Palette is Little Endian 4 byte RGB0 values. No alpha.
There *might* be up to 256 palette entries.
If number of colors is reported as zero, assume 256 color entires.
The Pixels are 1 byte index values.
INSERT PADDING BYTES TO GO UP TO NEXT DWORD AT END OF ROW. SET THEM TO 0x00.
The rows are stored in reverse order (bottom to top).


4bit ... Palette & Color Data:
====================================================================================
The Palette is Little Endian 4 byte RGB0 values. No alpha.
There *might* be up to 16 palette entries.
If number of colors is reported as zero, assume 16 color entires.
The Pixels are nybble-length index values.
INSERT PADDING BYTES TO GO UP TO NEXT DWORD AT END OF ROW. SET THEM TO 0x00.
The rows are stored in reverse order (bottom to top).


Mask Data:
====================================================================================
Is a string of bytes with mask bits starting at MSB and going towards LSB.
There are ((imagewidth+31)>>5) DWORDS per row in *BIG ENDIAN* order.
Like the color data, there is a set of DWORDS for each row.
The rows are stored in reverse order (bottom to top).
Set unused padding bits/pixels at end of each row to 1. 
0 indicates opaque and 1 indicates transparent.


1bit ... XOR Mask, AND Mask, & Color Data:
====================================================================================
The Palette is Little Endian 4 byte RGB0 values. No alpha.
There should be exactly 2 palette entries: usually 0x00000000 and 0x00FFFFFF.
The two masks follow the Mask Data format decribed above.
The following results from combining two mask bits:
    XOR AND RESULT:
     0   0  Color #0 (Black)
     0   1  Transparent
     1   0  Color #1 (White)
     1   1  Invert Destination Bitmap

我当然不会把它留在这里。有代码!

以下代码将加载给定图标位置的所有图标图像并将其转换为 32bpp BITMAP 的矢量。如果加载给定的图像失败,它就不会被添加到矢量中(或者,在损坏的图标的情况下,它很可能会生成损坏的图像,所以要小心)。

该代码不支持单色图像中的“反转”颜色,并且只会生成仍然具有零 alpha 的不同颜色。

警告:包含一些伪代码以将内容缩短为基本要素。

图标加载器代码(支持:EXE、DLL、32bit ICL、ICO):

// Code written by Simion32.
// Please feel free to use it anywhere. 
// Credit would be nice but isn't required.

#include "include.h" //std::vectors and whatever else you need
#include <allegro.h>
#include <winalleg.h> //Allegro and Win32
#include "Shellapi.h"

// In the following block, the (required!!) pragmas
// force correct data alignment. Needed in at least GCC.
#pragma pack( push, 1 ) 
typedef struct
{
    BYTE                bWidth;         // Width, in pixels, of the image
    BYTE                bHeight;        // Height, in pixels, of the image
    BYTE                bColorCount;    // Number of colors in image (0 if >=8bpp)
    BYTE                bReserved;      // Reserved ( must be 0)
    WORD                wPlanes;        // Color Planes
    WORD                wBitCount;      // Bits per pixel
    DWORD               dwBytesInRes;   // How many bytes in this resource?
    DWORD               dwImageOffset;  // Where in the file is this image?
} ICONDIRENTRY, *LPICONDIRENTRY;
typedef struct
{
    WORD                idReserved;     // Reserved (must be 0)
    WORD                idType;         // Resource Type (1 for icons)
    WORD                idCount;        // How many images?
    ICONDIRENTRY        idEntries[1];   // An entry for each image (idCount of 'em)
} ICONDIR, *LPICONDIR;
typedef struct
{
   BITMAPINFOHEADER     icHeader;       // DIB header
   RGBQUAD              icColors[1];    // Color table
   BYTE                 icXOR[1];       // DIB bits for XOR mask
   BYTE                 icAND[1];       // DIB bits for AND mask
} ICONIMAGE, *LPICONIMAGE;
#pragma pack( pop)
#pragma pack( push, 2 )
typedef struct
{
   BYTE                 bWidth;         // Width, in pixels, of the image
   BYTE                 bHeight;        // Height, in pixels, of the image
   BYTE                 bColorCount;    // Number of colors in image (0 if >=8bpp)
   BYTE                 bReserved;      // Reserved
   WORD                 wPlanes;        // Color Planes
   WORD                 wBitCount;      // Bits per pixel
   DWORD                dwBytesInRes;   // total size of the RT_ICON resource referenced by the nID member.
   WORD                 nID;            // resourceID of RT_ICON (LockResource to obtain a pointer to its ICONIMAGE)
} GRPICONDIRENTRY, *LPGRPICONDIRENTRY;
typedef struct 
{
   WORD                 idReserved;     // Reserved (must be 0)
   WORD                 idType;         // Resource type (1 for icons)
   WORD                 idCount;        // How many images?
   GRPICONDIRENTRY      idEntries[1];   // The entries for each image
} GRPICONDIR, *LPGRPICONDIR;
#pragma pack( pop )




uint32_t Convert16BitToARGB(uint16_t value)
{
    return (0xFF000000|((value >>  7) & 0x0000F8)|((value <<  6) & 0x00F800)|((value << 19) & 0xF80000));
}
uint32_t GetMaskBit(uint8_t* data, int x, int y, int w, int h)
{
    uint32_t mask_data_rowsize = (((w+31)>>5) * 4);
    return ((~(data[(mask_data_rowsize * ((h-1)-y)) + (x >> 3)] >> (0x07 - (x & 0x07))) & 1) * 0xFFFFFFFF);
}
uint32_t GetColorMonochrome(uint8_t* xordata, uint8_t* anddata, int x, int y, int w, int h, uint32_t* pal)
{
    uint32_t mask_data_rowsize = (((w+31)>>5) * 4);
    uint32_t xor_bit = (((xordata[(mask_data_rowsize * ((h-1)-y)) + (x >> 3)] >> (0x07 - (x & 0x07))) << 1) & 2);
    uint32_t and_bit = (((anddata[(mask_data_rowsize * ((h-1)-y)) + (x >> 3)] >> (0x07 - (x & 0x07)))     ) & 1);
    uint32_t value = (xor_bit | and_bit);
    return pal[value];
}



BITMAP* CreateBmp32bppFromIconResData(void* data, int size, int depth, int w, int h, int colors)
{
    char* pngheader = "\211PNG\r\n\032\n";
    char* cpd = (char*)data;
    bool is_png = ((cpd[0]==pngheader[0])
                && (cpd[1]==pngheader[1])
                && (cpd[2]==pngheader[2])
                && (cpd[3]==pngheader[3])
                && (cpd[4]==pngheader[4])
                && (cpd[5]==pngheader[5])
                && (cpd[6]==pngheader[6])
                && (cpd[7]==pngheader[7]));
    if(is_png)
    {
        //###########################################################
        //#  PSEUDO-CODE: Somehow convert the PNG file into a bitmap.
        BITMAP* result = ConvertPngFileToBmp32bpp(data, size);
        return result;
    }
    else
    {
        uint32_t ignore_size = ((BITMAPINFOHEADER*)(data))->biSize;
        BITMAP* bmp = create_bitmap_ex(32,w,h);
        uint32_t pixel_count = (w * h);
        uint32_t color_data_size = ((((((w * depth)+7) >> 3) +3) & ~3) * h);
        switch(depth)
        {
            default: return bmp; break;
            case 32:
            {
                uint32_t* src = (uint32_t*)(((uint8_t*)data) + ignore_size);
                for(int yy = h-1; yy >= 0; --yy){
                    for(int xx = 0; xx < w; ++xx){
                        _putpixel32(bmp,xx,yy,src[0]);
                        src++;
                    }
                    //There should never be any padding to jump over here.
                }
                return bmp;
            }
            break;
            case 24:
            {
                uint32_t* src = (uint32_t*)(((uint8_t*)data) + ignore_size);
                uint8_t* bitmask = (uint8_t*)(((uint8_t*)data) + ignore_size + color_data_size);
                int padding_checker = 0;
                for(int yy = h-1; yy >= 0; --yy){
                    for(int xx = 0; xx < w; ++xx){
                        _putpixel32(bmp,xx,yy,((src[0] & 0x00FFFFFF) | 0xFF000000) & GetMaskBit(bitmask, xx, yy, w, h));
                        src++;
                        src = (uint32_t*)(((uint8_t*)src)-1); //go back a byte due to packing
                        padding_checker += 3;
                        padding_checker &= 3;
                    }
                    //This loop jumps over any padding bytes.
                    while(padding_checker)
                    {
                        src = (uint32_t*)(((uint8_t*)src)+1);
                        padding_checker++;
                        padding_checker &= 3;
                    }
                }
                return bmp;
            }
            break;
            case 16:
            {
                //Note: there might be a color table present! ignore it.
                uint16_t* src = (uint16_t*)(((uint8_t*)data) + ignore_size + (colors << 2));
                uint8_t* bitmask = (uint8_t*)(((uint8_t*)data) + ignore_size + (colors << 2) + color_data_size);
                int padding_checker = 0;
                for(int yy = h-1; yy >= 0; --yy){
                    for(int xx = 0; xx < w; ++xx){
                        _putpixel32(bmp,xx,yy,Convert16BitToARGB(src[0]) & GetMaskBit(bitmask, xx, yy, w, h));
                        src++;
                        padding_checker += 2;
                        padding_checker &= 3;
                    }
                    //This loop jumps over any padding bytes.
                    while(padding_checker)
                    {
                        src = (uint16_t*)(((uint8_t*)src)+1);
                        padding_checker++;
                        padding_checker &= 3;
                    }
                }
                return bmp;
            }
            break;
            case 8:
            {
                if(colors > 256) colors = 256; //Color Count must be restricted to 256 entries at the most.
                if(colors <=  0) colors = 256; //Color Count might be reported as zero. This means 256.
                uint8_t* src = (((uint8_t*)data) + ignore_size + (colors << 2));
                uint32_t* pal = ((uint32_t*)(((uint8_t*)data) + ignore_size));
                uint8_t* bitmask = (uint8_t*)(((uint8_t*)data) + ignore_size + (colors << 2) + color_data_size);
                int padding_checker = 0;
                for(int yy = h-1; yy >= 0; --yy){
                    for(int xx = 0; xx < w; ++xx){
                        uint8_t color = src[0];
                        if(color < colors){
                            _putpixel32(bmp,xx,yy,(pal[color] | 0xFF000000) & GetMaskBit(bitmask, xx, yy, w, h));
                        }else{
                            _putpixel32(bmp,xx,yy,0x00FF00FF);
                        }
                        src++;
                        padding_checker++;
                        padding_checker &= 3;
                    }
                    //This loop jumps over any padding bytes.
                    while(padding_checker)
                    {
                        src++;
                        padding_checker++;
                        padding_checker &= 3;
                    }
                }
                return bmp;
            }
            break;
            case 4:
            {
                if(colors > 16) colors = 16; //Color Count must be restricted to 16 entries at the most.
                if(colors <= 0) colors = 16; //Color Count might be reported as zero. This means 16.
                uint8_t* src = (((uint8_t*)data) + ignore_size + (colors << 2));
                uint32_t* pal = ((uint32_t*)(((uint8_t*)data) + ignore_size));
                uint8_t* bitmask = (uint8_t*)(((uint8_t*)data) + ignore_size + (colors << 2) + color_data_size);
                int padding_checker = 0;
                for(int yy = h-1; yy >= 0; --yy){
                    for(int xx = 0; xx < w; ++xx){
                        uint8_t color = src[0];
                        if(xx & 1) color = ( color       & 0x0F);
                        else       color = ((color >> 4) & 0x0F);
                        if(color < colors){
                            _putpixel32(bmp,xx,yy,(pal[color] | 0xFF000000) & GetMaskBit(bitmask, xx, yy, w, h));
                        }else{
                            _putpixel32(bmp,xx,yy,0x00FF00FF);
                        }
                        if(xx & 1)
                        {
                            src++;
                            padding_checker++;
                            padding_checker &= 3;
                        }
                    }
                    //if the pointer hasn't incremented to the next byte yet, do so.
                    if(w & 1) //odd width
                    {
                        src++;
                        padding_checker++;
                        padding_checker &= 3;
                    }
                    //This loop jumps over any padding bytes.
                    while(padding_checker)
                    {
                        src++;
                        padding_checker++;
                        padding_checker &= 3;
                    }
                }
                return bmp;
            }
            break;
            case 1:
            {
                if(colors >  2) colors = 2; //Color Count must be restricted to 2 entries at the most.
                if(colors <= 0) colors = 2; //Color Count might be reported as zero. This means 2.
                uint32_t* pal        = (uint32_t*)(((uint8_t*)data) + ignore_size);
                uint8_t* bitmaskXOR = (uint8_t*)(((uint8_t*)data) + ignore_size + (colors << 2));
                uint8_t* bitmaskAND = (uint8_t*)(((uint8_t*)data) + ignore_size + (colors << 2) + color_data_size);
                uint32_t  ret_colors[4] = {pal[0]|0xFF000000, 0x00FF00FF, pal[1]|0xFF000000, 0x0000FF00};
                for(int yy = h-1; yy >= 0; --yy){
                    for(int xx = 0; xx < w; ++xx){
                        _putpixel32(bmp,xx,yy,GetColorMonochrome(bitmaskXOR, bitmaskAND, xx, yy, w, h, ret_colors));
                    }
                }
                return bmp;
            }
            break;
        }
        return bmp;
    }
}



vector< BITMAP* > ResourceToBitmapVector(HMODULE hm, HRSRC hr, bool is_group_icon)
{
    vector< BITMAP* > results;
    if(is_group_icon)
    {
        HGLOBAL hg = LoadResource(hm,hr);
        GRPICONDIR* gd = (GRPICONDIR*)LockResource(hg);
        if(gd->idType == 1)
        {
            for(int i = 0; i < gd->idCount; ++i)
            {
                //WARNING: The GRPICONDIRENTRY's data might be wrong!
                GRPICONDIRENTRY* ie = (GRPICONDIRENTRY*)&(gd->idEntries[i]);
                HRSRC ihr = FindResource(hm,MAKEINTRESOURCE(ie->nID),RT_ICON);
                if(ihr != NULL)
                {
                    HGLOBAL ihg = LoadResource(hm,ihr);
                    void* data = (void*)LockResource(ihg);
                    DWORD size = SizeofResource(hm,ihr);
                    uint32_t b = ((BITMAPINFOHEADER*)(data))->biBitCount;
                    uint32_t w = ((BITMAPINFOHEADER*)(data))->biWidth;
                    uint32_t h = (((BITMAPINFOHEADER*)(data))->biHeight >> 1); //icons have doubled height value.
                    uint32_t c = ((BITMAPINFOHEADER*)(data))->biClrUsed;
                    results.push_back(CreateBmp32bppFromIconResData(data, size, b, w, h, c));
                }
            }
        }
    }
    else
    {
        HGLOBAL ihg = LoadResource(hm,hr);
        void* data = (void*)LockResource(ihg);
        DWORD size = SizeofResource(hm,hr);
        uint32_t b = ((BITMAPINFOHEADER*)(data))->biBitCount;
        uint32_t w = ((BITMAPINFOHEADER*)(data))->biWidth;
        uint32_t h = (((BITMAPINFOHEADER*)(data))->biHeight >> 1); //icons have doubled height value.
        uint32_t c = ((BITMAPINFOHEADER*)(data))->biClrUsed;
        results.push_back(CreateBmp32bppFromIconResData(data, size, b, w, h, c));
    }
    return results;
}



vector< BITMAP* > IconFileToBitmapVector(void* icon_data, uint32_t icon_size)
{
    vector< BITMAP* > results;
    ICONDIR* gd = (ICONDIR*)icon_data;
    if(gd->idType == 1) 
    {
        for(int i = 0; i < gd->idCount; ++i)
        {
            //WARNING: The ICONDIRENTRY's data might be wrong!
            DWORD offset = gd->idEntries[i].dwImageOffset;
            DWORD size = gd->idEntries[i].dwBytesInRes;
            void* data = (void*)(((uint8_t*)icon_data) + ((uint32_t)offset));
            uint32_t b = ((BITMAPINFOHEADER*)(data))->biBitCount;
            uint32_t w = ((BITMAPINFOHEADER*)(data))->biWidth;
            uint32_t h = (((BITMAPINFOHEADER*)(data))->biHeight >> 1); //icons have doubled height value.
            uint32_t c = ((BITMAPINFOHEADER*)(data))->biClrUsed;
            results.push_back(CreateBmp32bppFromIconResData(data, size, b, w, h, c));
        }
    }
    return results;
}



vector< BITMAP* > UnearthIconResource(string& file, bool self_refrence, bool res_index, int index)
{
    #define LOAD_IGNORE_CODE_AUTHZ_LEVEL 0x00000010

    //prevents a negative indexing error 
    // (the boolean res_index handles whether it's icon index VS resource ID)
    index = abs(index); 

    vector< BITMAP* > results; //array of results to return (pointers to 32bpp images)

    //extract and 'demangle' the file extension by convertng to lowercase.
    string ext = get_file_extension(file.c_str());
    for(int i = 0; i < ext.size(); ++i) ext[i] = tolower(ext[i]);

    bool is_icl = false;
    if((ext == "exe") || (ext == "dll") || (ext == "scr") || (is_icl = (ext == "icl")))
    {
        // Portable Executable Resource (works for both DLL and EXE)
        // Also works for any 32bit Icon Library (Microangelo Studio?)
        HMODULE hm = LoadLibraryEx(file.c_str(), NULL, 
            (DONT_RESOLVE_DLL_REFERENCES | LOAD_IGNORE_CODE_AUTHZ_LEVEL | LOAD_LIBRARY_AS_DATAFILE));
        if(hm != NULL)
        {
            HRSRC hr;
            if(!self_refrence)
            {
                if(res_index)
                {
                    //The icon we want is at the resource ID (==index)
                    bool is_single_icon = false;
                    hr = FindResource(hm,MAKEINTRESOURCE(index),RT_GROUP_ICON);
                    if(hr == NULL)
                    {
                        hr = FindResource(hm,MAKEINTRESOURCE(index),RT_ICON);
                        is_single_icon = (hr != NULL);
                    }
                    if(hr != NULL)
                    {
                        results = ResourceToBitmapVector(hm, hr, !is_single_icon);
                    }
                }
                else
                {
                    //The icon we want is the (index)'th icon in the file
                    //We must preform a manual search for the resource ID!
                    //WARNING: Using EnumResourceNames() *DOES NOT WORK PROPERLY* for this.
                    for(int nicon = 0, i = 0; i < 0x8000; ++i)
                    {
                        bool is_single_icon = false;
                        hr = FindResource(hm,MAKEINTRESOURCE(i),RT_GROUP_ICON);
                        if(hr != NULL)
                        {
                            if(nicon == index)
                            {
                                results = ResourceToBitmapVector(hm, hr, true);
                                break;
                            }
                            nicon++;
                        }
                    }
                }
            }
            else
            {
                //The icon we want is the "first" icon in the file. 
                //Happens when location is a %1.
                //We must preform a manual search for the resource ID!
                //WARNING: Using EnumResourceNames() *DOES NOT WORK PROPERLY* for this.
                for(int i = 0; i < 0x8000; ++i)
                {
                    bool is_single_icon = false;
                    hr = FindResource(hm,MAKEINTRESOURCE(i),RT_GROUP_ICON);
                    if(hr != NULL)
                    {
                        results = ResourceToBitmapVector(hm, hr, true);
                        break;
                    }
                }
            }
            FreeLibrary(hm);
        }
        else /*if(is_icl)
        {//OH NOES. We have to load a *16bit* .icl file!
            //not supported yet. sorry. left as another excecise to the programmer.
        }*/
    }
    else if(ext == "ico")
    {
        //Single Icon File

        //###################################################
        //#  PSEUDO-CODE: Do the file loading yourself ;)
        void* data_pointer = NULL;
        uint32_t data_size = 0;
        if(data_pointer = MyLoadFile(file.c_str(), &data_size))
        {
            if(data_size)
            {
                results = IconFileToBitmapVector((void*)data_pointer, data_size);
            }
        }
        MyCloseFile(data_pointer);
    }
    return results;
}

我认为这几乎涵盖了所有内容...

我应该提到的最后一件事:一定要忽略来自图标目录条目的大小和位深度信息。他们常常是错误的。我看到一些 256 色图像报告为 24 位,导致图像加载器内部的数据损坏。

于 2013-05-23T17:46:47.973 回答
0

如果它不必是平台独立的:

不久前,我写了一个小类来读取文件并提取所有图标。它使用 HICON 检索 std::vector。使用 GetIconInfo,您可以检索像素数据的 HBITMAP 和像素掩码。

该函数有点启发式。它扫描二进制数据以查找典型图标开始并尝试加载它们。该功能也适用于 dll、exe 或 icl(仅包含图标资源的 16 位 dll)

#ifndef __ICON_LIST_H__
#define __ICON_LIST_H__

#include <windows.h>
#include <vector>



class IconFile: public std::vector<HICON>{
public:

  IconFile(){};

  IconFile(std::string i_filename){
    addIconsFromFile(i_filename);
  };

  int addIconsFromFile(std::string i_fileName){
    int iCount=0;
    HANDLE file = CreateFile( i_fileName.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
    if(file!=INVALID_HANDLE_VALUE){
      int   size   = GetFileSize(file,NULL);
      DWORD actRead;
      BYTE* buffer = new BYTE[size];
      ReadFile(file, buffer, size, &actRead, NULL);
      CloseHandle(file);
      int ind = -1;
      for(int p = 0; p< size-4; ++p){
        if(buffer[p]==40 && buffer[p+1]==0 && buffer[p+2]==0 && buffer[p+3]==0){
          HICON icon = CreateIconFromResourceEx(&buffer[p], size-p, true, 0x00030000,0,0,0);
          if(icon){
            ++iCount;
            this->push_back(icon);
          }
        }
      }     
      delete[] buffer;
    }
    return iCount;
  };

};


#endif //__ICON_LIST_H__
于 2013-05-02T19:15:21.923 回答