【发布时间】:2011-04-17 10:03:17
【问题描述】:
如果我将资源添加到 Resources.resx,它们是否嵌入在可执行文件中?
我在某处读到资源存储在程序集中,但是项目中的所有文件(包括输出文件夹中的文件)都是程序集的一部分吗?
或者,程序集只是编译器生成的文件和模块,而资源不包含在程序集中?
有人能准确说明这是如何工作的吗?
【问题讨论】:
标签: .net visual-studio resources
如果我将资源添加到 Resources.resx,它们是否嵌入在可执行文件中?
我在某处读到资源存储在程序集中,但是项目中的所有文件(包括输出文件夹中的文件)都是程序集的一部分吗?
或者,程序集只是编译器生成的文件和模块,而资源不包含在程序集中?
有人能准确说明这是如何工作的吗?
【问题讨论】:
标签: .net visual-studio resources
您添加到 C# 程序的资源存储在 PE 的资源部分 二进制。
例如,如果我添加一个字符串MyTestString,其值为"Charles is Cool"
如果我在十六进制编辑器中打开编译后的二进制文件,我可以看到我的字符串:
很酷,但它是怎么来的?
资源编辑器生成 Resources.Designer.cs,下面是它生成的内容
/// <summary>
/// Looks up a localized string similar to Charles is Cool.
/// </summary>
internal static string MyTestString {
get {
return ResourceManager.GetString("MyTestString", resourceCulture);
}
}
但是等等...我在这里的任何地方都没有看到"Charles is Cool"...它去哪儿了? GetString() 是从哪里得到的?
好吧,最终它是grovels for the resource(MSFT 的术语,不是我的),我想我们应该将其视为ManifestBasedResourceGroveler,它最终将我们带到extern GetResource(),这是一个明确的迹象,表明我们已经脱离了.NET 世界...您知道这意味着...
我们可以查看 coreclr 存储库以了解其实现方式的示例,
如果你要在这里追踪代码,你最终会来到PEDecoder::GetResource()
const void *PEDecoder::GetResource(COUNT_T offset, COUNT_T *pSize) const
{
CONTRACT(const void *)
{
INSTANCE_CHECK;
PRECONDITION(CheckCorHeader());
PRECONDITION(CheckPointer(pSize, NULL_OK));
NOTHROW;
GC_NOTRIGGER;
}
CONTRACT_END;
IMAGE_DATA_DIRECTORY *pDir = &GetCorHeader()->Resources;
// 403571: Prefix complained correctly about need to always perform rva check
if (CheckResource(offset) == FALSE)
return NULL;
void * resourceBlob = (void *)GetRvaData(VAL32(pDir->VirtualAddress) + offset);
// Holds if CheckResource(offset) == TRUE
PREFIX_ASSUME(resourceBlob != NULL);
if (pSize != NULL)
*pSize = GET_UNALIGNED_VAL32(resourceBlob);
RETURN (const void *) ((BYTE*)resourceBlob+sizeof(DWORD));
}
这基本上是从 PE 头中找到偏移量(参见IMAGE_COR20_HEADER)。查看Portable Executable article on Wikipedia,您会看到svg 图像有一个ResourceTable 部分(RVA,又名Relative Virtual Address)
我在这里得到的是,资源绝不是 C# 或 .NET 功能,它们只是 PE 二进制格式一直具有的托管 API。
请注意,我所说的所有内容都适用于任意数据,如果您要向资源中添加一些二进制文件,Resources 会将其作为byte[] 呈现给您,但实际上它会将其编码为其他内容。
虽然在 Visual Studio 中打开 resx 文件会为您提供导入的二进制文件的相当无趣的路径,但请注意,如果您以 JetBrains DotPeek 之类的方式打开已编译的二进制文件并查看 resx 文件,路径到文件已被替换为字符串,
<data name="binary" type="System.Byte[], mscorlib">
<value>CGdTCb7vyv7AD/6rze8=</value>
</data>
虽然我无法在 Visual Studio 端找到任何代码来证明这一点,但我猜这个字符串是(二进制)资源文件中字节的 base64 编码版本,因为运行 Convert.ToBase64String(Resources.binary) 给了我相同的结果在已编译二进制文件的 resx 文件中找到的字符串。对于那些想在家尝试的人,我的二进制文件只包含08 67 53 09 BE EF CA FE C0 0F FE AB CD EF。
【讨论】:
嵌入的资源存储在 DLL 或 EXE 文件中。
【讨论】: