以编程方式将资源嵌入到.NET程序集中

7
我有一个已编译的.NET程序集,其中嵌入了一个特定的资源文件(名为'Script.xml')。我需要以编程方式将其更换为另一个文件。
是否可以在不重新编译源代码的情况下进行更改?
目前,我通过搜索我知道在文件中存在的文本来实现这一点,并且效果很好。但是,我需要在另一个项目中执行此操作,而我不知道资源文件的任何内容,因此需要找到另一种方法。
FileStream exe = new FileStream(currentexe, FileMode.Open);

//find xml part of exefile
string find = "<?xml version=\"1.0\"?>";
string lastchars = new string(' ', find.Length);
while (exe.CanRead) {
    lastchars = lastchars.Substring(1) + (char)exe.ReadByte();
    if (lastchars == find) {
        exe.Seek(-find.Length, SeekOrigin.Current);
        break;
    }
}

//output serialized script
int bytenum = 0;
foreach (byte c in xml) {
    if (c == 0) break;
    exe.WriteByte(c);
    bytenum++;
}

//clean out extra data
while (bytenum++ < ScriptFileSize) {
    exe.WriteByte(0x20);
}
exe.Close();
4个回答

4
您当前的机制非常脆弱 - 如果使用签名程序集(因为哈希值会更改)或者需要用较大的资源替换一个资源(因为所有其他偏移量可能会移动),则无法正常工作。此外,它在字符编码方面存在问题,而且找到文件中正确位置的一般机制也存在问题,但考虑到我认为这种方法起初并不合适,所以这些问题相对不那么重要。
如果您需要可替换的资源,我建议将它们放在另一个完全不具有程序集相对脆弱格式的文件中。

资源文件可以变得更大,而且仍然能够正常工作,因为它可以用空格填充(最大尺寸:'ScriptFileSize')。不幸的是,这个项目需要将其包含在单个文件中。 - Nick Whaley
@Nick:这实际上意味着它不能比现有资源更大,因为现有资源将始终是ScriptFileSize。我真的很想重新设计一下。如果你非常必须这样做,使用一个知道程序集文件格式的库(如Cecil-http://www.mono-project.com/Cecil),但尽可能避免这样做。 - Jon Skeet
@Jon:没错,我忘了提到汇编代码最初已经编译了大量填充以匹配常量ScriptFileSize。我给了足够的空间,从未遇到过空间不足的情况,而且目前在数百台计算机上成功运行。但我真的非常想重新设计它,这就是为什么我在这里发布的原因。 - Nick Whaley

4
您可以使用 Cecil 打开程序集并插入资源(我这样做)。可能会有所不同。

1
如果您使用Cecil正确读取和重新生成PDB,则不会破坏PDB。 - Jb Evain
我猜想是这样的,但1.5年前我无法弄清如何做到。你有例子吗? - Anton Tykhyy
那时它已经可以工作了。但是现在,随着新的API,您需要按照此处指示进行操作:https://github.com/jbevain/cecil/wiki/Debug-symbols - Jb Evain

1

你可能正在寻找System.Runtime.Emit来动态编译程序集。


1

您可以使用反射动态构建程序集,具体来说是使用AssemblyBuilder类,并将资源包含在您动态构建的程序集中。我不确定是否可能使用反射来反汇编现有程序集(尽管现在我很感兴趣)。

如果可能的话,我会选择另一种方法。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接