嵌入式资源存储在.NET应用程序中的哪个位置?

Mir*_*ria 6 .net resources visual-studio

如果我向Resources.resx添加资源,它们是否嵌入在可执行文件中?

我已经读过资源存储在程序集中的某个地方,但项目中的所有文件(包括输出文件夹中的文件)都是程序集的一部分?

或者,汇编只是由编译器和资源生成的文件和模块不包含在程序集中?

有人可以澄清这是如何工作的吗?

jrh*_*jrh 7

快速回答

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

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

添加了字符串的资源编辑器的屏幕截图

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

十六进制编辑器的屏幕截图

很酷,但是它是怎么到这里的?

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

但是等等...我没有看到"Charles is Cool"这里的任何地方...它去了哪里?从哪里GetString()得到它?

好吧,最终它会屈服于资源(MSFT 的术语,不是我的),我想我们应该将其视为 a ManifestBasedResourceGroveler,这最终让我们成为extern GetResource(),这是我们已经脱离 .NET 宇宙边缘的明确信号......你知道这意味着...

CoreCLR 方面

我们可以查看 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));
}
Run Code Online (Sandbox Code Playgroud)

它基本上找到了相对于 PE 标头的偏移量(参见 参考资料IMAGE_COR20_HEADER)。查看Wikipedia 上的 Portable Executable 文章,您将看到 svg 图像有一个 ResourceTable 部分(RVA,又名相对虚拟地址

我在这里得到的是,资源绝不是 C# 或 .NET 功能,它们只是 PE 二进制格式始终具有的托管 API。

对于任意二进制资源

请注意,我所说的所有内容都适用于任意数据,如果您要向资源中添加一些二进制文件,Resources则会将其作为 a 呈现给您byte[],但实际上它会将其编码为其他内容。

虽然在 Visual Studio 中打开 resx 文件会为您提供导入的二进制文件的相当无趣的路径,但请注意,如果您在JetBrains DotPeek之类的工具中打开已编译的二进制文件并查看 resx 文件,则该文件的路径具有被替换为字符串,

<data name="binary" type="System.Byte[], mscorlib">
    <value>CGdTCb7vyv7AD/6rze8=</value>
</data>
Run Code Online (Sandbox Code Playgroud)

虽然我无法在 Visual Studio 端找到任何代码来证明这一点,但我猜测这个字符串是(二进制)资源文件中字节的 base64 编码版本,因为运行给Convert.ToBase64String(Resources.binary)我提供了与编译后的字符串相同的字符串二进制的 resx 文件。对于那些想在家尝试这个的人,我的二进制文件刚刚包含08 67 53 09 BE EF CA FE C0 0F FE AB CD EF.


Dav*_*nan 5

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