使用ICON动态修改exe文件图标

17 篇文章 3 订阅
前言:这两天为exe文件做一个随机图标的功能,要求每次运行后图标都动态改变,在网上找了很多代码,都有一部分缺陷,参考了一些文档后进行了修改,现在在此进行总结:
一个icon资源(可以是*.ico文件,也可以是windows资源节区里的icon group),可以包含多张图片。这些图片有着各自的size或者颜色深度,这些图片可以是bmp格式或者png格式(vista之后支持,一般256*256时使用)


****************如果我们在win32环境下打开一个*.ico文件**************************

Icon文件结构由两部分组成:icon文件头和多张图片数据,图片可以是bmp、png:

Icon文件头
typedef struct
{
    WORD idReserved; 	//必须为0
    WORD idType; 		//如果是icons则必须是1
    WORD idCount; 		//表示有多少张图片
} ICONDIR, *LPICONDIR;
其中idReserved必须是0;idType对于ICON文件来说必须是1;idCount指明icon文件有多少张图片,也就指明了接下来有多少个ICONDIRENTRY结构体数据。
//在文件头后面则是 idCount个结构体  ICONDIRENTRY idEntries[x]; 

每张图片详情结构体,图片数据不在这其中
typedef struct
{
    BYTE bWidth;
    BYTE bHeight; 
    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;

//下面例子为从一个*.ico文件中更改exe文件的图标
void changedExeIcon(LPCTSTR lpExeName, LPCTSTR lpIconFile)
{
	LPICONDIRENTRY pIconDirEntry(NULL);
	LPGRPICONDIR pGrpIconDir(NULL);
	HEADER header;
	LPBYTE pIconBytes(NULL);
	HANDLE hIconFile(NULL);
	DWORD dwRet(0), nSize(0), nGSize(0), dwReserved(0);
	HANDLE hUpdate(NULL);
	BOOL ret(FALSE);
	WORD i(0);

	//打开图标文件  
	hIconFile = CreateFile(lpIconFile, GENERIC_READ, NULL, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	if (hIconFile == INVALID_HANDLE_VALUE)
	{
		return;
	}
	//读取文件头部信息  
	ret = ReadFile(hIconFile, &header, sizeof(HEADER), &dwReserved, NULL);
	if (!ret)
	{
		CloseHandle(hIconFile);
		return;
	}
	//建立每一个图标的目录信息存放区域  
	pIconDirEntry = (LPICONDIRENTRY)new BYTE[header.idCount*sizeof(ICONDIRENTRY)];
	if (pIconDirEntry == NULL)
	{
		CloseHandle(hIconFile);
		return;
	}
	//从Icon文件中读取每一个图标的目录信息  
	ret = ReadFile(hIconFile, pIconDirEntry, header.idCount*sizeof(ICONDIRENTRY), &dwReserved, NULL);
	if (!ret)
	{
		delete[] pIconDirEntry;
		CloseHandle(hIconFile);
		return;
	}
	//建立EXE文件中RT_GROUP_ICON所需的数据结构存放区域  
	nGSize = sizeof(GRPICONDIR) + header.idCount*sizeof(ICONDIRENTRY);
	pGrpIconDir = (LPGRPICONDIR)new BYTE[nGSize];
	//填充信息,这里相当于一个转换的过程  
	pGrpIconDir->idReserved = header.idReserved;
	pGrpIconDir->idType = header.idType;
	pGrpIconDir->idCount = header.idCount;
	//复制信息并设置每一个图标对应的ID。ID为位置索引号  
	for (i = 0; i < header.idCount; i++)
	{
		pGrpIconDir->idEntries[i].bWidth = pIconDirEntry[i].bWidth;
		pGrpIconDir->idEntries[i].bHeight = pIconDirEntry[i].bHeight;
		pGrpIconDir->idEntries[i].bColorCount = pIconDirEntry[i].bColorCount;
		pGrpIconDir->idEntries[i].bReserved = pIconDirEntry[i].bReserved;
		pGrpIconDir->idEntries[i].wPlanes = pIconDirEntry[i].wPlanes;
		pGrpIconDir->idEntries[i].wBitCount = pIconDirEntry[i].wBitCount;
		pGrpIconDir->idEntries[i].dwBytesInRes = pIconDirEntry[i].dwBytesInRes;
		pGrpIconDir->idEntries[i].nID = i;
	}
	//开始更新EXE中的图标资源,ID定为最小0,如果原来存在0ID的图标信息则被替换为新的。  
	hUpdate = BeginUpdateResource(lpExeName, false);
	if (hUpdate != NULL)
	{
		//首先更新RT_GROUP_ICON信息  
		ret = UpdateResource(hUpdate, RT_GROUP_ICON, MAKEINTRESOURCE(128), MAKELANGID(LANG_CHINESE, SUBLANG_SYS_DEFAULT), (LPVOID)pGrpIconDir, nGSize);
		if (!ret)
		{
			delete[] pIconDirEntry;
			delete[] pGrpIconDir;
			CloseHandle(hIconFile);
			return;
		}
		//接着的是每一个Icon的信息存放  
		for (i = 0; i < header.idCount; i++)
		{
			//Icon的字节数  
			nSize = pIconDirEntry[i].dwBytesInRes;
			//偏移文件的指针到当前图标的开始处  
			dwRet = SetFilePointer(hIconFile, pIconDirEntry[i].dwImageOffset, NULL, FILE_BEGIN);
			if (dwRet == INVALID_SET_FILE_POINTER)
			{
				break;
			}
			//准备pIconBytes来存放文件里的Byte信息用于更新到EXE中。  
			delete[] pIconBytes;
			pIconBytes = new BYTE[nSize];
			ret = ReadFile(hIconFile, (LPVOID)pIconBytes, nSize, &dwReserved, NULL);
			if (!ret)
			{
				break;
			}
			//更新每一个ID对应的RT_ICON信息  
			ret = UpdateResource(hUpdate, RT_ICON, MAKEINTRESOURCE(pGrpIconDir->idEntries[i].nID), MAKELANGID(LANG_CHINESE, SUBLANG_SYS_DEFAULT), (LPVOID)pIconBytes, nSize);
			if (!ret)
			{
				break;
			}
		}
		//结束EXE资源的更新操作  
		if (pIconBytes != NULL)
		{
			delete[] pIconBytes;
		}
		EndUpdateResource(hUpdate, false);
	}
	//清理资源并关闭Icon文件,到此更新操作结束!  
	delete[] pGrpIconDir;
	delete[] pIconDirEntry;
	CloseHandle(hIconFile);
}


****************如果我们在一个exe或者ico的资源文件中使用icon**************************
它的结构有些微改变,如下:

注意:g_hModule为本进程实例句柄,也可以通过g_hModule = LoadLibrary(_TEXT("C:\\Ohter.exe")); 来获取其他exe中的资源文件,达到复制图标的效果。

//在使用时,这儿需要重新设置结构体对其方式,不然系统会默认为4个字节,我们就不能正确读取资源文件了
#pragma pack( push ) 
#pragma pack( 2 )  //我们调整为2个字节对其
typedef struct tagGRPICONDIR
{
	WORD idReserved;
	WORD idType;
	WORD idCount;
	GRPICONDIRENTRY idEntries[1];
}GRPICONDIR, *LPGRPICONDIR;
#pragma pack( pop ) //恢复对齐状态

#pragma pack( push )
#pragma pack( 2 )
typedef struct tagGRPICONDIRENTRY
{
	BYTE bWidth;
	BYTE bHeight;
	BYTE bColorCount;
	BYTE bReserved;
	WORD wPlanes;
	WORD wBitCount;
	DWORD dwBytesInRes;
	WORD nID;
}GRPICONDIRENTRY, *LPGRPICONDIRENTRY;;
#pragma pack( pop )

//下面例子为从一个Icon资源文件中更改exe文件的图标
void changedExeIcon(LPCTSTR lpExeName, UINT ulIconID)
{
	HRSRC	hRsrc = NULL;
	HGLOBAL	hGlobal = NULL;
	HANDLE  hUpdateRes = NULL;
	LPVOID	lpRes = NULL;
	LPGRPICONDIR lpIcon;

	if ((hRsrc = FindResource(g_hModule, MAKEINTRESOURCE(ulIconID), RT_GROUP_ICON)) == NULL)//获取ID为ulIconID1的Icon图标资源
		return ;
	if ((hGlobal = LoadResource(g_hModule, hRsrc)) == NULL)
		return ;
	if ((lpIcon = (LPGRPICONDIR)LockResource(hGlobal)) == NULL)
		return ;

	
	hUpdateRes = BeginUpdateResource(lpExeName, FALSE);
	if (hUpdateRes == NULL)
		return;

	DWORD szRes = SizeofResource(g_hModule, hRsrc);

	//128是WINDOWS系统默认图标
	//更新exe的RT_GROUP_ICON
	BOOL bSuc = UpdateResource(hUpdateRes, RT_GROUP_ICON, MAKEINTRESOURCE(128), MAKELANGID(LANG_CHINESE, SUBLANG_SYS_DEFAULT), LockResource(hGlobal), szRes);

	//读取Icon中每一个图片
	for (size_t i = 0; i < lpIcon->idCount; i++)
	{
		if ((hRsrc = FindResource(g_hModule, MAKEINTRESOURCE(lpIcon->idEntries[i].nID), RT_ICON)) == NULL)
		{
			return;
		}
		if ((hGlobal = LoadResource(g_hModule, hRsrc)) == NULL)
		{
			return;
		}
		szRes = SizeofResource(g_hModule, hRsrc);
		//更新exe相应的RT_ICON
		UpdateResource(hUpdateRes, RT_ICON, MAKEINTRESOURCE(i), MAKELANGID(LANG_CHINESE, SUBLANG_SYS_DEFAULT), LockResource(hGlobal), szRes);
		//这儿有个疑问,在DLL中修改exe则为下面这样的格式,不知道为什么?
		//UpdateResource(hUpdateRes, RT_ICON, MAKEINTRESOURCE(lpIcon->idEntries[i].nID), MAKELANGID(LANG_CHINESE, SUBLANG_SYS_DEFAULT), LockResource(hGlobal), szRes);
	}
	EndUpdateResource(hUpdateRes, FALSE);
}

本文参考:http://blog.csdn.net/hbxtlhx/article/details/5026725

  • 0
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值