当前位置: 首页 > news >正文

【Delphi】操纵EXE文件中的主图标(MAINICON)

RT_GROUP_ICON 是 Windows 可执行文件中用于存储图标资源的重要结构,它本质上是一个图标目录,用于管理多个不同尺寸和颜色深度的图标图像。

参考:Winuser.h) (资源类型 - Win32 apps | Microsoft Learn

基本概念

RT_GROUP_ICON 资源类型的 ID 为 14(0x0E),它与 RT_ICON 资源配合使用:

  • RT_GROUP_ICON:作为图标目录,描述了一组图标的元数据
  • RT_ICON:存储实际的图标图像数据

这种结构类似于 ICO 文件,但有重要区别:RT_GROUP_ICON 不直接存储图像数据,而是通过资源 ID 引用对应的 RT_ICON 资源。

数据结构定义

GRPICONDIR 结构(图标目录头)

typedef struct {WORD  idReserved;   // 保留字段,必须为 0WORD  idType;       // 资源类型,图标为 1WORD  idCount;      // 图标数量GRPICONDIRENTRY idEntries[1]; // 图标条目数组
} GRPICONDIR, *LPGRPICONDIR;

GRPICONDIRENTRY 结构(图标条目)

typedef struct {BYTE   bWidth;      // 图标宽度(像素)BYTE   bHeight;     // 图标高度(像素)BYTE   bColorCount; // 颜色数量(0 表示 >=8bpp)BYTE   bReserved;   // 保留字段,必须为 0WORD   wPlanes;     // 颜色平面数WORD   wBitCount;   // 每像素位数DWORD  dwBytesInRes;// 资源数据大小(字节)WORD   nID;         // 对应的 RT_ICON 资源 ID
} GRPICONDIRENTRY, *LPGRPICONDIRENTRY;

与 ICO 文件格式的区别

特征ICO 文件格式RT_GROUP_ICON 格式
最后一个字段dwImageOffset(文件偏移量)nID(资源 ID)
数据存储直接包含图像数据仅包含引用,图像数据在 RT_ICON 中
用途磁盘文件存储EXE/DLL 资源存储

完整结构示例

假设一个包含 2 个图标的 RT_GROUP_ICON 资源:

[GRPICONDIR]
idReserved: 0x0000
idType:     0x0001
idCount:    0x0002[GRPICONDIRENTRY 1]
bWidth:      32
bHeight:     32
bColorCount: 0
bReserved:   0
wPlanes:     1
wBitCount:   32
dwBytesInRes: 4096
nID:         1[GRPICONDIRENTRY 2]
bWidth:      16
bHeight:     16
bColorCount: 0
bReserved:   0
wPlanes:     1
wBitCount:   32
dwBytesInRes: 1024
nID:         2

Delphi 中处理 RT_GROUP_ICON 的示例代码

读取 RT_GROUP_ICON 资源

usesWindows, SysUtils;typeTGRPICONDIR = recordidReserved: Word;idType: Word;idCount: Word;idEntries: array[0..0] of TGRPICONDIRENTRY;end;PGRPICONDIR = ^TGRPICONDIR;TGRPICONDIRENTRY = recordbWidth: Byte;bHeight: Byte;bColorCount: Byte;bReserved: Byte;wPlanes: Word;wBitCount: Word;dwBytesInRes: DWORD;nID: Word;end;PGRPICONDIRENTRY = ^TGRPICONDIRENTRY;procedure ReadGroupIcon(const ExeFileName: string);
varhModule: THandle;hResource: THandle;pResource: PByte;pGroupIcon: PGRPICONDIR;pEntry: PGRPICONDIRENTRY;i: Integer;
beginhModule := LoadLibraryEx(PChar(ExeFileName), 0, LOAD_LIBRARY_AS_DATAFILE);if hModule = 0 thenRaiseLastOSError;tryhResource := FindResource(hModule, MAKEINTRESOURCE(1), RT_GROUP_ICON);if hResource = 0 thenRaiseLastOSError;pResource := LockResource(LoadResource(hModule, hResource));if pResource = nil thenRaiseLastOSError;pGroupIcon := PGRPICONDIR(pResource);Writeln(Format('图标数量: %d', [pGroupIcon.idCount]));Writeln('资源类型: ', pGroupIcon.idType);pEntry := @pGroupIcon.idEntries[0];for i := 0 to pGroupIcon.idCount - 1 dobeginWriteln(Format('图标 %d:', [i + 1]));Writeln(Format('  尺寸: %dx%d', [pEntry.bWidth, pEntry.bHeight]));Writeln(Format('  颜色深度: %d bpp', [pEntry.wBitCount]));Writeln(Format('  数据大小: %d 字节', [pEntry.dwBytesInRes]));Writeln(Format('  RT_ICON ID: %d', [pEntry.nID]));Writeln;Inc(pEntry);end;finallyFreeLibrary(hModule);end;
end;

更新 EXE 文件的图标资源

procedure UpdateExeIcon(const IconFilename, ExeFilename: string);
varhUpdate: THandle;IconStream: TFileStream;IconData: array of Byte;IconSize: DWORD;IconDir: TIconDir;IconEntry: TIconDirEntry;IconImage: TIconImage;i: Integer;
begin// 打开图标文件IconStream := TFileStream.Create(IconFilename, fmOpenRead or fmShareDenyNone);tryIconSize := IconStream.Size;SetLength(IconData, IconSize);IconStream.ReadBuffer(IconData[0], IconSize);// 解析 ICO 文件头Move(IconData[0], IconDir, SizeOf(TIconDir));if (IconDir.idReserved <> 0) or (IconDir.idType <> 1) thenraise Exception.Create('无效的 ICO 文件');// 开始更新 EXE 资源hUpdate := BeginUpdateResource(PChar(ExeFilename), False);if hUpdate = 0 thenRaiseLastOSError;try// 更新 RT_GROUP_ICONif not UpdateResource(hUpdate, RT_GROUP_ICON, MAKEINTRESOURCE(1), MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), @IconData[0], IconSize) thenRaiseLastOSError;// 更新对应的 RT_ICON 资源for i := 0 to IconDir.idCount - 1 dobeginMove(IconData[SizeOf(TIconDir) + i * SizeOf(TIconDirEntry)], IconEntry, SizeOf(TIconDirEntry));// 读取图标图像数据Move(IconData[IconEntry.dwImageOffset], IconImage, SizeOf(TIconImage));// 更新 RT_ICON 资源if not UpdateResource(hUpdate, RT_ICON, MAKEINTRESOURCE(i + 1), MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), @IconData[IconEntry.dwImageOffset], IconEntry.dwBytesInRes) thenRaiseLastOSError;end;// 完成更新if not EndUpdateResource(hUpdate, False) thenRaiseLastOSError;exceptEndUpdateResource(hUpdate, True);raise;end;finallyIconStream.Free;end;
end;

关键要点

  1. RT_GROUP_ICON 与 RT_ICON 的关系:前者是目录,后者是实际数据
  2. 资源 ID 的重要性:GRPICONDIRENTRY.nID 必须与对应的 RT_ICON 资源 ID 匹配
  3. 多语言支持:可以为不同语言创建不同的 RT_GROUP_ICON 资源
  4. 兼容性:从 Windows Vista 开始支持 PNG 压缩的图标数据
  5. 资源更新:更新图标时需要同时更新 RT_GROUP_ICON 和对应的 RT_ICON 资源

理解 RT_GROUP_ICON 格式对于处理 Windows 应用程序图标、资源编辑和 EXE 文件修改等任务非常重要。

http://www.dtcms.com/a/537477.html

相关文章:

  • 彭州建设网站陕西省建设执业资格注册中心网站
  • 济南企业上云网站建设如何让网站自适应手机
  • nginx基础入门篇-nginx部署-Yum
  • Leetcode每日一练--43
  • Nacos 配置中心:动态配置管理
  • cpp / c++零基础两周速成教学
  • 免费微场景制作网站深圳外贸公司有哪些公司
  • Selenium定位元素的方法css和xpath的区别
  • 什么网站可以自学ps做贵宾卡互联网营销师
  • 建站公司 深圳巴西网站后缀
  • LeetCode 3. 无重复字符的最长子串解析
  • 给你一个新的网站怎么做2017网站备案抽查
  • 杭州网站做的好公司公司品牌网络推广方案
  • PyTorch Geometric 图神经网络实战利器
  • 《深入浅出统计学》学习笔记(一)
  • 从登录场景看通用序列化协议:JSON 与 Protobuf 实践
  • 天津网站优化软件一个公司可以做两个网站吗
  • 常用的网站开发做网站软件要钱吗
  • 怎样做一家网站傻瓜式建站软件下载
  • 【软考架构】案例题 - 数据库系统与缓存设计:在MySQL数据库设计中,反规范化的常见方法
  • 公司做网站都需要什么流程sofish wordpress主题
  • 顺德 网站开发 招聘网站排名软件推荐
  • 三维空间点绕Y轴旋转的数学原理与Python实现
  • 大模型未来发展可能有哪些趋势
  • 数电基础:TTL构成的常见门电路
  • 从0开始学python(day2)
  • 天蓝色网站网站建设遇到的问题及对策
  • 专业网站建设分类标准石家庄企业网络推广
  • MySQL Workbench 8.0.44中文汉化
  • 网站建设一条龙包括哪些服务wordpress主页在