【问题标题】:Where are embedded resources stored in a .NET app?.NET 应用程序中的嵌入式资源存储在哪里?
【发布时间】:2011-04-17 10:03:17
【问题描述】:

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

我在某处读到资源存储在程序集中,但是项目中的所有文件(包括输出文件夹中的文件)都是程序集的一部分吗?

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

有人能准确说明这是如何工作的吗?

【问题讨论】:

    标签: .net visual-studio resources


    【解决方案1】:

    快速解答

    您添加到 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);
        }
    }
    

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

    好吧,最终它是grovels for the resource(MSFT 的术语,不是我的),我想我们应该将其视为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));
    }
    

    这基本上是从 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。

    【讨论】:

      【解决方案2】:

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

      【讨论】:

      • @Miria:如果您使用.NET Reflector 的副本查看资源,您可以在程序集中看到自己的资源。不幸的是,它不再是免费下载的。
      • 谢谢。我的意思是,所以 EXE 是程序集的一部分,因此嵌入式资源在程序集中,对吗?
      猜你喜欢
      • 2011-02-18
      • 1970-01-01
      • 1970-01-01
      • 2011-01-29
      • 1970-01-01
      • 1970-01-01
      • 2018-09-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多