.NET应用程序中嵌入的资源存储在哪里?

7
如果我将资源添加到Resources.resx中,它们会被嵌入到可执行文件中吗?
我曾经在某个地方读到过资源存储在程序集中,但是项目中的所有文件(包括输出文件夹中的文件)都是程序集的一部分吗?
还是说程序集只是编译器生成的文件和模块,而资源不包含在程序集中?
有人能够准确说明这是如何工作的吗?
2个回答

7

简单回答

您添加到C#程序中的资源存储在PE二进制文件的资源部分中。

例如,如果我添加一个字符串MyTestString,其值为"Charles is Cool"

A screenshot of the resource editor with the string added to it

如果我在十六进制编辑器中打开已编译的二进制文件,我就可以看到我的字符串:

A screenshot from a hex editor

很酷,但它是如何到达这里的?
C#方面
资源编辑器生成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()从哪里获取它?
嗯,最终它会搜索资源(MSFT的术语,不是我的),我想我们应该考虑这是一个ManifestBasedResourceGroveler,最终带我们到extern GetResource(),这是一个明确的迹象,表明我们已经跌出了.NET宇宙...你知道那意味着什么...
核心CLR方面
我们可以查看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)。请查看维基百科上的可移植可执行文件文章,您会发现svg图像有一个ResourceTable部分(RVA,又称相对虚拟地址

我的意思是,资源绝不是C#或.NET功能,它们只是一种管理API,可以进入PE二进制格式始终具有的内容。

对于任意二进制资源

请注意,我所说的一切都适用于任意数据,如果您要将某些二进制文件添加到资源中,则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


5
嵌入式资源存储在DLL或EXE文件中。

@Miria:如果你使用 .NET Reflector 的副本查看程序集,你就可以自己看到资源了。不幸的是,它现在已经不是免费下载了。 - Cody Gray
谢谢。我的意思是,EXE文件是程序集的一部分,因此嵌入资源在程序集内部,对吗? - Miria

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