最近,我制作了一个程序,该程序加载可执行文件或DLL文件,枚举其中的所有图标资源,然后将每个图标资源另存为.ico文件在文件夹中。但是它使用直方图(如this post中所述)来避免保存重复的图标(看起来相同的图标)。
该程序首先从用户处获取两条路径(用户必须在控制台窗口中键入它们)。其中一个是exe或dll文件的路径,另一个是要保存.ico文件的文件夹的路径。
然后,程序通过调用LoadLibraryEx
加载exe或dll文件,并通过调用EnumResourceNames
枚举图标资源。
传递给EnumResourceNames
的回调函数将每个非重复的图标资源另存为具有唯一名称的.ico文件。保存文件的名称是这样的:1.ico
,2.ico
,3.ico
,4.ico
,.etc
我的完整代码和问题
问题是我的程序创建的是损坏或未知的.ico文件,不是真实的文件。
我的意思是,有些保存的图标有奇怪的图像,而有些根本看不到!即使我使用BITMAPFILEHEADER
函数将WriteFile
结构写入每个.ico文件。
只需编译并运行我的代码,然后在控制台窗口中键入以下内容:
C:\Windows\System32\shell32.dll
然后,键入要保存.ico文件的现有文件夹的路径。
接下来,至少等待4至7秒钟,直到操作完成。
然后打开该文件夹,然后查看图标!他们真可笑!
以下是我的代码。很抱歉,如果注释中或变量和函数的名称中有一些拼写错误。无论如何,只有函数
main()
和EnumIcons()
很重要,请务必阅读代码下方的说明。#include <iostream>
#include <conio.h>
#include <Windows.h>
#include <string>
#include <vector>
using namespace std;
string folderPath;
//Variables to store the number of
//successfully extracted icons.
UINT nSucceed = 0, nFail = 0;
typedef struct tagHISTOGRAM {
float bucket1; //Range 0-63
float bucket2; //Range 64-127
float bucket3; //Range 128-191
float bucket4; //Range 192-255
} HISTOGRAM, *PHISTOGRAM;
typedef struct tagIOV {
SIZE dimensions; //Width and height of the image
HISTOGRAM hgRed; //Histogram for red channel
HISTOGRAM hgGreen; //Histogram for green channel
HISTOGRAM hgBlue; //Histogram for blue channel
} IMAGE_OVERVIEW, *PIMAGE_OVERVIEW;
#define isInRange(n, s, e) (s <= n) && (n <= e)
//Constant used for the last parameter of CreateIconFromResource
#define ICO_VER 0x00030000
//Vector which stores IMAGE_OVERVIEW stuctures discribing all
//icons processed. When a new icon is being processed, the
//program checks all previous structures in the vector and
//then add the corresponding IMAGE_OVERVIEW structure to the
//vector.
vector<IMAGE_OVERVIEW> theIcons;
inline void incrementAppropriateBucket(PHISTOGRAM phg, BYTE pixel)
{
if (isInRange(pixel, 0, 63))
phg->bucket1++;
else if (isInRange(pixel, 64, 127))
phg->bucket2++;
else if (isInRange(pixel, 128, 191))
phg->bucket3++;
else if (isInRange(pixel, 192, 255))
phg->bucket4++;
}
//The following function divides each bucket total by the number
//of pixels in the entire image.
inline void finalizeHistogram(PHISTOGRAM phg, DWORD nPixels)
{
phg->bucket1 /= nPixels;
phg->bucket2 /= nPixels;
phg->bucket3 /= nPixels;
phg->bucket4 /= nPixels;
}
BOOL createImageOverview(HBITMAP hBmp, PIMAGE_OVERVIEW iov)
{
BITMAPINFO bmpInfo = {};
bmpInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
HDC DC = CreateCompatibleDC(NULL);
SelectObject(DC, hBmp);
if (!GetDIBits(DC, hBmp, 0, 0, NULL, &bmpInfo, DIB_RGB_COLORS))
{
ReleaseDC(NULL, DC);
DeleteDC(DC);
return FALSE;
}
bmpInfo.bmiHeader.biBitCount = 32;
bmpInfo.bmiHeader.biCompression = BI_RGB;
bmpInfo.bmiHeader.biHeight = abs(bmpInfo.bmiHeader.biHeight);
iov->dimensions.cx = bmpInfo.bmiHeader.biWidth;
iov->dimensions.cy = bmpInfo.bmiHeader.biHeight;
BYTE* pixels = new BYTE[bmpInfo.bmiHeader.biSizeImage];
if (!GetDIBits(DC, hBmp, 0, bmpInfo.bmiHeader.biHeight, (PVOID) pixels, &bmpInfo, DIB_RGB_COLORS))
{
delete[] pixels;
ReleaseDC(NULL, DC);
DeleteDC(DC);
return FALSE;
}
for (LONG Y = bmpInfo.bmiHeader.biHeight - 1;Y >= 0;Y--)
for (LONG X = 0;X < bmpInfo.bmiHeader.biWidth;X++)
{
BYTE R = pixels[(bmpInfo.bmiHeader.biWidth * Y + X) * 4 + 2];
incrementAppropriateBucket(&(iov->hgRed), R);
BYTE G = pixels[(bmpInfo.bmiHeader.biWidth * Y + X) * 4 + 1];
incrementAppropriateBucket(&(iov->hgGreen), G);
BYTE B = pixels[(bmpInfo.bmiHeader.biWidth * Y + X) * 4];
incrementAppropriateBucket(&(iov->hgBlue), B);
}
DWORD nPixels = bmpInfo.bmiHeader.biWidth * bmpInfo.bmiHeader.biHeight;
finalizeHistogram(&(iov->hgRed), nPixels);
finalizeHistogram(&(iov->hgGreen), nPixels);
finalizeHistogram(&(iov->hgBlue), nPixels);
delete[] pixels;
ReleaseDC(NULL, DC);
DeleteDC(DC);
return TRUE;
}
float sumUpBucketDifferances(const HISTOGRAM hg1, const HISTOGRAM hg2)
{
float result = 0;
result += abs(hg1.bucket1 - hg2.bucket1);
result += abs(hg1.bucket2 - hg2.bucket2);
result += abs(hg1.bucket3 - hg2.bucket3);
result += abs(hg1.bucket4 - hg2.bucket4);
return result;
}
float compareImages(const IMAGE_OVERVIEW iov1, const IMAGE_OVERVIEW iov2)
{
float result = 0;
result += sumUpBucketDifferances(iov1.hgRed, iov2.hgRed);
result += sumUpBucketDifferances(iov1.hgGreen, iov2.hgGreen);
result += sumUpBucketDifferances(iov1.hgBlue, iov2.hgBlue);
return result;
}
BOOL isDuplicate(const IMAGE_OVERVIEW iov)
{
size_t s = theIcons.size();
for (size_t i = 0;i < s;i++)
{
if ((theIcons[i].dimensions.cx != iov.dimensions.cx) ||
(theIcons[i].dimensions.cy != iov.dimensions.cy))
continue;
if (compareImages(theIcons[i], iov) < 0.1)
return TRUE;
}
return FALSE;
}
BOOL CALLBACK EnumIcons(HMODULE hModule, LPCTSTR lpszType, LPTSTR lpszName, LONG_PTR lParam)
{
HRSRC hRes = FindResource(hModule, lpszName, lpszType);
if (!hRes)
{
nFail++;
return TRUE;
}
DWORD icoSize = SizeofResource(hModule, hRes);
if (!icoSize)
{
nFail++;
return TRUE;
}
HGLOBAL hIcoData = LoadResource(hModule, hRes);
if (!hIcoData)
{
nFail++;
return TRUE;
}
BYTE* icoData = (BYTE *) LockResource(hIcoData);
if (!icoData)
{
FreeResource(hIcoData);
nFail++;
return TRUE;
}
//Checking whether the icon is dupplicate
HICON hIcon = CreateIconFromResource(icoData, icoSize, TRUE, ICO_VER);
if (!hIcon)
{
FreeResource(hIcoData);
nFail++;
return TRUE;
}
ICONINFO ii;
if (!GetIconInfo(hIcon, &ii))
{
DestroyIcon(hIcon);
FreeResource(hIcoData);
nFail++;
return TRUE;
}
IMAGE_OVERVIEW iov;
ZeroMemory(&iov, sizeof(IMAGE_OVERVIEW));
BOOL r = createImageOverview(ii.hbmColor, &iov);
DeleteObject(ii.hbmColor);
DeleteObject(ii.hbmMask);
DestroyIcon(hIcon);
if (!r)
{
FreeResource(hIcoData);
nFail++;
return TRUE;
}
if (isDuplicate(iov))
{
FreeResource(hIcoData);
nFail++;
return TRUE;
}
theIcons.push_back(iov);
//End of checking whether the icon is dupplicate
//Note that the first icon is saved as 1.ico,
//the second is saved as 2.ico, and so on. So
//the number of the current icon is equal to
//the number of the previously saved icons + 1
int icoNumber = nSucceed + 1;
PSTR strIcoNumber = (PSTR) VirtualAlloc((LPVOID) NULL, 10, MEM_COMMIT, PAGE_READWRITE);
itoa(icoNumber, strIcoNumber, 10);
string icoPath(folderPath);
icoPath.append(strIcoNumber);
icoPath.append(".ico");
VirtualFree(strIcoNumber, 0, MEM_RELEASE);
PCSTR strIcoPath = icoPath.c_str();
HANDLE ico = CreateFile(strIcoPath, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (ico == INVALID_HANDLE_VALUE)
{
FreeResource(hIcoData);
nFail++;
return TRUE;
}
DWORD bytesWritten;
BITMAPFILEHEADER bfh;
bfh.bfType = 0x4d42;
bfh.bfSize = icoSize + sizeof(BITMAPFILEHEADER);
bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
bfh.bfReserved1 = bfh.bfReserved2 = 0;
r = WriteFile(ico, &bfh, sizeof(BITMAPFILEHEADER), &bytesWritten, NULL);
if (!r)
{
FreeResource(hIcoData);
CloseHandle(ico);
nFail++;
return TRUE;
}
r = WriteFile(ico, icoData, icoSize, &bytesWritten, NULL);
FreeResource(hIcoData);
CloseHandle(ico);
if (!r)
{
nFail++;
return TRUE;
}
nSucceed++;
return TRUE;
}
void main()
{
cout << "Enter the path where your EXE or DLL is located:" << endl;
string modulePath;
getline(cin, modulePath);
cout << "Now, enter the path of the folder where the .ico files are to be saved:" << endl;
getline(cin, folderPath);
//If the folder path doesn't have a trailing backslash, add one!
if (folderPath.rfind('\\') != folderPath.length() - 1)
folderPath.push_back('\\');
cout << "Extracting icons..." << endl;
PCSTR strModulePath = modulePath.c_str();
HMODULE hModule = LoadLibraryEx(strModulePath, NULL, LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE | LOAD_LIBRARY_AS_IMAGE_RESOURCE);
if (!hModule)
{
cout << "Unable to load the DLL or EXE." << endl;
getch();
return;
}
BOOL result = EnumResourceNames(hModule, MAKEINTRESOURCE(RT_ICON), (ENUMRESNAMEPROC) EnumIcons, NULL);
FreeLibrary(hModule);
if (!result)
{
cout << "Unable to extract icons." << endl;
getch();
return;
}
cout << nSucceed << " icons were successfully extracted." << endl;
cout << "Failed to extract " << nFail << " icons." << endl;
getch();
}
好吧,我们有四个全局变量。其中之一是
folderPath
。如前所述,我们从用户那里获取文件夹的路径。此操作在main()
函数中执行,并且路径存储在folderPath
变量中。我将此变量定义为全局变量,因为它可以被EnumIcons()
函数和main()
函数访问。现在,看看
main()
函数。这很容易理解。因此,在
main()
函数中,在从用户处获取输入后,我们先调用LoadLibraryEx
,然后再调用EnumResourceNames
,并向其传递指向EnumIcons
回调函数的指针。 EnumIcons
函数为成功保存的每个图标增加nSucceed
全局变量,为失败保存的每个图标或重复的图标增加nFail
。现在,看看
EnumIcons
函数,该函数保存在EXE或DLL文件中找到的每个非重复图标。该函数内部的代码很清晰,除了一部分可以检查图标是否重复的代码。该部分代码以以下注释开头:
//Checking whether the icon is dupplicate
并以以下注释结束:
//End of checking whether the icon is dupplicate
我只建议您跳过该功能的那部分,因为它与我的主要问题无关。在
EnumIcons
函数中,我调用了诸如FindResource
,LoadResource
,LockResource
,SizeofResource
,CreateFile
和WriteFile
之类的函数。只需检查我是否调用了这些函数并正确进行了错误检查即可。不要关注检测重复图标的部分。
解:
今天,我使用@Barmak Shemirani的答案中的信息对我的代码进行了一些更改并解决了问题。我只是想知道
#pragma
指令是什么(在定义ICONDIR
和ICONDIRENTRY
结构之前和之后使用的指令)。这是我修改的代码:编辑:该代码已进行了较小的改进。
#include <iostream>
#include <conio.h>
#include <Windows.h>
#include <string>
#include <vector>
using namespace std;
//Variables to store the number of
//successfully extracted icons and
//the icons that are dupplicate or
//failed to extract.
UINT nSucceed = 0, nFail = 0;
typedef struct tagHISTOGRAM {
float bucket1; //Range 0-63
float bucket2; //Range 64-127
float bucket3; //Range 128-191
float bucket4; //Range 192-255
} HISTOGRAM, *PHISTOGRAM;
typedef struct tagIOV {
SIZE dimensions; //Width and height of the image
HISTOGRAM hgRed; //Histogram for red channel
HISTOGRAM hgGreen; //Histogram for green channel
HISTOGRAM hgBlue; //Histogram for blue channel
} IMAGE_OVERVIEW, *PIMAGE_OVERVIEW;
#define isInRange(n, s, e) (s <= n) && (n <= e)
//Constant used for the last parameter of CreateIconFromResource
#define ICO_VER 0x00030000
//Vector which stores IMAGE_OVERVIEW stuctures discribing all
//icons processed. When a new icon is being processed, the
//program checks all previous structures in the vector and
//then add the corresponding IMAGE_OVERVIEW structure to the
//vector.
vector<IMAGE_OVERVIEW> theIcons;
#pragma pack(push, 2)
typedef struct
{
BYTE bWidth;
BYTE bHeight;
BYTE bColorCount;
BYTE bReserved;
WORD wPlanes;
WORD wBitCount;
DWORD dwBytesInRes;
DWORD dwImageOffset;
} ICONDIRENTRY, *LPICONDIRENTRY;
typedef struct
{
WORD idReserved;
WORD idType;
WORD idCount;
ICONDIRENTRY idEntries[1];
} ICONDIR, *LPICONDIR;
#pragma pack(pop)
inline void incrementAppropriateBucket(PHISTOGRAM phg, BYTE pixel)
{
if (isInRange(pixel, 0, 63))
phg->bucket1++;
else if (isInRange(pixel, 64, 127))
phg->bucket2++;
else if (isInRange(pixel, 128, 191))
phg->bucket3++;
else if (isInRange(pixel, 192, 255))
phg->bucket4++;
}
//The following function divides each bucket total by the number
//of pixels in the entire image.
inline void finalizeHistogram(PHISTOGRAM phg, DWORD nPixels)
{
phg->bucket1 /= nPixels;
phg->bucket2 /= nPixels;
phg->bucket3 /= nPixels;
phg->bucket4 /= nPixels;
}
BOOL createImageOverview(HBITMAP hBmp, PIMAGE_OVERVIEW iov)
{
BITMAPINFO bmpInfo = {};
bmpInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
HDC DC = CreateCompatibleDC(NULL);
SelectObject(DC, hBmp);
if (!GetDIBits(DC, hBmp, 0, 0, NULL, &bmpInfo, DIB_RGB_COLORS))
{
DeleteDC(DC);
return FALSE;
}
bmpInfo.bmiHeader.biBitCount = 32;
bmpInfo.bmiHeader.biCompression = BI_RGB;
bmpInfo.bmiHeader.biHeight = abs(bmpInfo.bmiHeader.biHeight);
iov->dimensions.cx = bmpInfo.bmiHeader.biWidth;
iov->dimensions.cy = bmpInfo.bmiHeader.biHeight;
BYTE* pixels = new BYTE[bmpInfo.bmiHeader.biSizeImage];
if (!GetDIBits(DC, hBmp, 0, bmpInfo.bmiHeader.biHeight, (PVOID) pixels, &bmpInfo, DIB_RGB_COLORS))
{
delete[] pixels;
DeleteDC(DC);
return FALSE;
}
for (LONG Y = bmpInfo.bmiHeader.biHeight - 1;Y >= 0;Y--)
for (LONG X = 0;X < bmpInfo.bmiHeader.biWidth;X++)
{
BYTE R = pixels[(bmpInfo.bmiHeader.biWidth * Y + X) * 4 + 2];
incrementAppropriateBucket(&(iov->hgRed), R);
BYTE G = pixels[(bmpInfo.bmiHeader.biWidth * Y + X) * 4 + 1];
incrementAppropriateBucket(&(iov->hgGreen), G);
BYTE B = pixels[(bmpInfo.bmiHeader.biWidth * Y + X) * 4];
incrementAppropriateBucket(&(iov->hgBlue), B);
}
DWORD nPixels = bmpInfo.bmiHeader.biWidth * bmpInfo.bmiHeader.biHeight;
finalizeHistogram(&(iov->hgRed), nPixels);
finalizeHistogram(&(iov->hgGreen), nPixels);
finalizeHistogram(&(iov->hgBlue), nPixels);
delete[] pixels;
DeleteDC(DC);
return TRUE;
}
float sumUpBucketDifferances(const HISTOGRAM hg1, const HISTOGRAM hg2)
{
float result = 0;
result += abs(hg1.bucket1 - hg2.bucket1);
result += abs(hg1.bucket2 - hg2.bucket2);
result += abs(hg1.bucket3 - hg2.bucket3);
result += abs(hg1.bucket4 - hg2.bucket4);
return result;
}
float compareImages(const IMAGE_OVERVIEW iov1, const IMAGE_OVERVIEW iov2)
{
float result = 0;
result += sumUpBucketDifferances(iov1.hgRed, iov2.hgRed);
result += sumUpBucketDifferances(iov1.hgGreen, iov2.hgGreen);
result += sumUpBucketDifferances(iov1.hgBlue, iov2.hgBlue);
return result;
}
BOOL isDuplicate(const IMAGE_OVERVIEW iov)
{
size_t s = theIcons.size();
for (size_t i = 0;i < s;i++)
{
if ((theIcons[i].dimensions.cx != iov.dimensions.cx) ||
(theIcons[i].dimensions.cy != iov.dimensions.cy))
continue;
if (compareImages(theIcons[i], iov) < 0.1)
return TRUE;
}
return FALSE;
}
BOOL CALLBACK EnumIcons(HMODULE hModule, LPCTSTR lpszType, LPTSTR lpszName, LONG_PTR lParam)
{
if (!lParam)
return FALSE;
string folderPath = (char *) lParam;
HRSRC hRes = FindResource(hModule, lpszName, lpszType);
if (!hRes)
{
nFail++;
return TRUE;
}
DWORD icoSize = SizeofResource(hModule, hRes);
if (!icoSize)
{
nFail++;
return TRUE;
}
HGLOBAL hIcoData = LoadResource(hModule, hRes);
if (!hIcoData)
{
nFail++;
return TRUE;
}
BYTE* icoData = (BYTE *) LockResource(hIcoData);
if (!icoData)
{
FreeResource(hIcoData);
nFail++;
return TRUE;
}
HICON hIcon = CreateIconFromResource(icoData, icoSize, TRUE, ICO_VER);
if (!hIcon)
{
FreeResource(hIcoData);
nFail++;
return TRUE;
}
ICONINFOEX ii = {sizeof(ICONINFOEX)};
if (!GetIconInfoEx(hIcon, &ii))
{
DestroyIcon(hIcon);
FreeResource(hIcoData);
nFail++;
return TRUE;
}
BITMAP bmp;
if (!GetObject(ii.hbmColor, sizeof(BITMAP), &bmp))
{
DeleteObject(ii.hbmColor);
DeleteObject(ii.hbmMask);
DestroyIcon(hIcon);
FreeResource(hIcoData);
nFail++;
return TRUE;
}
ICONDIR icoDir = {0};
icoDir.idType = 1;
icoDir.idCount = 1;
icoDir.idEntries[0].bWidth = (BYTE) bmp.bmWidth;
icoDir.idEntries[0].bHeight = (BYTE) bmp.bmHeight;
icoDir.idEntries[0].wPlanes = bmp.bmPlanes;
icoDir.idEntries[0].wBitCount = bmp.bmBitsPixel;
icoDir.idEntries[0].dwBytesInRes = icoSize;
icoDir.idEntries[0].dwImageOffset = sizeof(ICONDIR);
//Checking whether the icon is duplicate
IMAGE_OVERVIEW iov;
ZeroMemory(&iov, sizeof(IMAGE_OVERVIEW));
BOOL r = createImageOverview(ii.hbmColor, &iov);
DeleteObject(ii.hbmColor);
DeleteObject(ii.hbmMask);
DestroyIcon(hIcon);
if (!r)
{
FreeResource(hIcoData);
nFail++;
return TRUE;
}
if (isDuplicate(iov))
{
FreeResource(hIcoData);
nFail++;
return TRUE;
}
theIcons.push_back(iov);
//End of checking whether the icon is dupplicate
//Note that the first icon is saved as 1.ico,
//the second is saved as 2.ico, and so on. So
//the number of the current icon is equal to
//the number of the previously saved icons + 1
int icoNumber = nSucceed + 1;
char* strIcoNumber = (char *) malloc(10);
itoa(icoNumber, strIcoNumber, 10);
string icoPath(folderPath);
icoPath.append(strIcoNumber);
icoPath.append(".ico");
HANDLE ico = CreateFile(icoPath.c_str(), GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (ico == INVALID_HANDLE_VALUE)
{
FreeResource(hIcoData);
nFail++;
return TRUE;
}
DWORD bytesWritten;
r = WriteFile(ico, &icoDir, sizeof(ICONDIR), &bytesWritten, NULL);
if (!r)
{
FreeResource(hIcoData);
CloseHandle(ico);
nFail++;
return TRUE;
}
r = WriteFile(ico, icoData, icoSize, &bytesWritten, NULL);
FreeResource(hIcoData);
CloseHandle(ico);
if (!r)
{
nFail++;
return TRUE;
}
nSucceed++;
return TRUE;
}
void main()
{
cout << "Enter the path where your EXE or DLL is located:" << endl;
string modulePath;
getline(cin, modulePath);
cout << "Now, enter the path of the folder where the .ico files are to be saved:" << endl;
string folderPath;
getline(cin, folderPath);
//If the folder path doesn't have a trailing backslash, add one!
if (folderPath.rfind('\\') != folderPath.length() - 1)
folderPath.push_back('\\');
cout << "Extracting icons..." << endl;
HMODULE hModule = LoadLibraryEx(modulePath.c_str(), NULL, LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE | LOAD_LIBRARY_AS_IMAGE_RESOURCE);
if (!hModule)
{
cout << "Unable to load the DLL or EXE." << endl;
getch();
return;
}
BOOL result = EnumResourceNames(hModule, MAKEINTRESOURCE(RT_ICON), (ENUMRESNAMEPROC) EnumIcons, (LONG_PTR) (folderPath.c_str()));
FreeLibrary(hModule);
if (!result)
{
cout << "Unable to extract icons." << endl;
getch();
return;
}
cout << nSucceed << " icons were successfully extracted." << endl;
cout << nFail << " icons were dupplicates or could not be extracted." << endl;
getch();
}
最佳答案
图标文件应以图 header ICONDIR
开头,而不是BITMAPFILEHEADER
。参见Icon reference
从FindResource
获得的字节可能包含PNG数据,而不是位图。最好避免在图标和位图之间进行转换。
初始化并写入图 header 之后,可以直接写入从FindResource
获得的字节,以避免任何转换。EnumResourceNames(... RT_ICON ...)
将枚举单独的图标,因此每个目标文件都包含一个图标。EnumResourceNames(... RT_GROUP_ICON ...)
将枚举图标组。您可以遍历各个组并将所有图标添加到一个文件中。
目前尚不清楚您查找重复项的标准是什么。使用RT_ICON
枚举,您会获得具有不同大小和颜色深度的相同图标,它们并非完全相同。您可以选择某些尺寸,例如32x32尺寸。要查找精确的重复项,可以从资源中计算字节的哈希值,然后比较哈希值。
#include <string>
#include <fstream>
#include <Windows.h>
#pragma pack(push, 2)
typedef struct
{
BYTE bWidth;
BYTE bHeight;
BYTE bColorCount;
BYTE bReserved;
WORD wPlanes;
WORD wBitCount;
DWORD dwBytesInRes;
DWORD dwImageOffset;
} ICONDIRENTRY, *LPICONDIRENTRY;
typedef struct
{
WORD idReserved;
WORD idType;
WORD idCount;
ICONDIRENTRY idEntries[1];
} ICONDIR, *LPICONDIR;
#pragma pack(pop)
BOOL CALLBACK EnumIcons(HMODULE hmodule, LPCTSTR type, LPTSTR lpszName, LONG_PTR ptr)
{
if(!ptr)
return FALSE;
std::string path = (const char*)ptr;
HRSRC hRes = FindResource(hmodule, lpszName, type);
if(!hRes)
return TRUE;
DWORD size = SizeofResource(hmodule, hRes);
HGLOBAL hg = LoadResource(hmodule, hRes);
BYTE* bytes = (BYTE*)LockResource(hg);
HICON hicon = CreateIconFromResource(bytes, size, TRUE, 0x00030000);
if(!hicon)
return TRUE;
if (IS_INTRESOURCE(lpszName))
path += std::to_string((int)lpszName);
else
path += lpszName;
path += std::string(".ico");
std::ofstream fout(path, std::ios::binary);
if(!fout)
return TRUE;
ICONINFOEX ii = { sizeof(ii) };
GetIconInfoEx(hicon, &ii);
ICONDIR hdr = { 0 };
hdr.idType = 1;
hdr.idCount = 1;
BITMAP bm;
GetObject(ii.hbmColor, sizeof(bm), &bm);
hdr.idEntries[0].bWidth = (BYTE)bm.bmWidth;
hdr.idEntries[0].bHeight = (BYTE)bm.bmHeight;
hdr.idEntries[0].wPlanes = bm.bmPlanes;
hdr.idEntries[0].wBitCount = bm.bmBitsPixel;
hdr.idEntries[0].dwBytesInRes = size;
hdr.idEntries[0].dwImageOffset = sizeof(ICONDIR);
fout.write((char*)&hdr, hdr.idEntries[0].dwImageOffset);
fout.write((char*)bytes, size);
DestroyIcon(hicon);
return TRUE;
}
int main()
{
std::string modulepath = "file.exe";
const char *dir = "c:\\test\\";
HMODULE hmodule = LoadLibraryEx(modulepath.c_str(), NULL,
LOAD_LIBRARY_AS_IMAGE_RESOURCE);
if(hmodule)
EnumResourceNames(hmodule, RT_ICON, (ENUMRESNAMEPROC)EnumIcons, (LONG_PTR)dir);
return 0;
}
ps,您不需要
VirtualAlloc
为自己的进程分配内存。您可以将malloc
或new
用于C++。更好的是,使用std::string
及其方法。
关于c++ - 将图标资源(不包括重复的图标)保存到磁盘,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51736843/