.NET 9中如何将.res文件正确嵌入PE文件并生成指定资源结构?
问题原因
直接将.res文件的原始字节写入资源节是错误的,PE文件的.rsrc节需要符合特定的资源目录层级结构,当前写法只是把.res的二进制数据直接塞入,没有构建正确的资源目录表头,导致7-Zip无法识别资源层级,只能把整个.rsrc节当成单个文件。
解决方案
需要解析.res文件中的资源内容,构建符合PE规范的资源目录结构,再通过ResourceSectionBuilder序列化到程序集中。以下是修改后的VersionInfoBuilder实现:
using System.Resources; using System.Reflection.Metadata; using System.Reflection.Metadata.Emit; internal class VersionInfoBuilder : ResourceSectionBuilder { private readonly ResourceDirectory _rootResourceDirectory; public VersionInfoBuilder(string resFilePath) { _rootResourceDirectory = new ResourceDirectory(0); if (string.IsNullOrWhiteSpace(resFilePath)) return; // 读取.res文件中的资源 using var resStream = File.OpenRead(resFilePath); using var resReader = new ResourceReader(resStream); // 版本信息对应的资源类型ID(PE规范定义的RT_VERSION) const int ResourceType_Version = 16; // 创建版本信息类型的目录 var versionTypeDir = new ResourceDirectory(ResourceType_Version); _rootResourceDirectory.Entries.Add(new ResourceDirectoryEntry(versionTypeDir)); // 遍历.res中的资源项(版本信息通常仅一项) foreach (DictionaryEntry entry in resReader) { var resourceData = (byte[])entry.Value; // 创建名称目录(默认名称ID为1) var nameDir = new ResourceDirectory(1); versionTypeDir.Entries.Add(new ResourceDirectoryEntry(nameDir)); // 创建语言目录(示例使用中文简体ID:2052,英文可改用1033) var langDir = new ResourceDirectory(2052); nameDir.Entries.Add(new ResourceDirectoryEntry(langDir)); // 添加资源数据条目 var dataEntry = new ResourceDataEntry( contentId: new BlobContentId(Guid.NewGuid()), data: resourceData, codePage: 0); langDir.Entries.Add(new ResourceDirectoryEntry(dataEntry)); } } protected override void Serialize(BlobBuilder builder, SectionLocation location) { _rootResourceDirectory.Serialize(builder, location); } }
说明
- 代码通过
ResourceReader解析.res文件内容,构建了PE资源要求的三层目录结构:资源类型目录→资源名称目录→语言目录,最终指向资源数据。 - 版本信息对应的资源类型固定为
RT_VERSION(ID=16),这是PE规范的标准定义。 - 语言ID可按需修改,比如英文环境用
1033,中文简体用2052。 - 替换原有
VersionInfoBuilder后重新生成程序集,7-Zip就能正确识别.rsrc为包含版本信息的文件夹结构。
内容的提问来源于stack exchange,提问作者Jonas _
相关产品推荐
相关产品推荐

