序
有的时候看见其他程序图标非常漂亮,想获取出来,在自己程序(非商业用途)里面使用。
但是windows自带的 ExtractIcon 函数获取的32x32的图标,分比例不高导致清晰度差。
而且有的应用程序或者模块有好几种图标,无法全部提取。
实现方案
之前有一篇替换应用程序里面的图标时,讲到的那几个函数,现在正好派上用场。
不清楚的小伙伴可以看一下之前那一篇编程笔记:替换windows应用图标。
通过里面的 FindResource、LoadResource 和 LockResource 就可以获取到资源数据。
唯一要注意的是该资源数据没有对应的资源数据头。
图标文件头
以我们课题讨论的,以图标资源为例,图标的文件头定义如下:
#pragma pack(push) //保正对齐状态
#pragma pack(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;
#pragma pack(pop)
#pragma pack(push) //保正对齐状态
#pragma pack(1)
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;
#pragma pack(pop)
然后只要我们根据对应的数据解释,填充对应数据即可。
初始数据可如下填充:
ICONDIR ico; // 资源头对象
memset(&ico, 0, sizeof(ICONDIR)); // 清零,这样那些必须为零的数据就不用填写了
ico.idType = 1;
ico.idCount = 1;
ico.idEntries[0].wPlanes = 1;
ico.idEntries[0].dwImageOffset = 22;
数据填充
上面初始化部分头数据已经填充完毕,接下来就是根据图片数据,对应更新图标宽高以及大小信息。
在资源函数枚举回调函数(这里命名为 SaveIcons )中,实现对数据的获取及填充。
具体实现代码如下:
BOOL CALLBACK SaveIcons(HMODULE hModule, LPCTSTR lpszType, LPTSTR lpszName, LONG lParam)
{
HRSRC hRes = FindResource(hModule, lpszName, lpszType);
HGLOBAL hResLoaded = LoadResource(hModule, hRes);
void* pData = LockResource(hResLoaded);
int nSizeOfIconRes = SizeofResource(hModule,hRes);
ico.idEntries[0].dwBytesInRes = nSizeOfIconRes*4; // 图标数据长度
int w = (byte)((char*)pData)[4]; // 该索引位置是图标尺寸
ico.idEntries[0].bWidth = ico.idEntries[0].bHeight = w; // 图标是正方形
// save data (略)
// 然后将 ico 的 22 字节数据写入文件,
// 后面追加 pData 的 nSizeOfIconRes*4 字节数据;
// 将图片命名为 "xxx.ico" 即可
UnlockResource(hResLoaded);
FreeResource(hResLoaded);
return TRUE;
}
void getIcons(const char *appName) // 传递需要获取的图标资源程序路径
{
HMODULE hModule = LoadLibraryExA(appName, NULL, LOAD_LIBRARY_AS_DATAFILE );
EnumResourceNames(hModule, RT_ICON, SaveIcons, NULL);
::FreeLibrary(hModule);
}
当然也可以直接通过UI应用去展示各个图片效果,保存需要的。
以下图片效果是我基于Qt做的界面运行效果:
总结
EnumResourceNames 函数资源类型哪里除了 RT_ICON 外还有好几个,
比如 RT_BITMAP 获取位图的,有兴趣的小伙伴可以自己实现。
如果觉得我写的还不错的话,求赞,求关注哦!(^▽^)