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

时间:2011-04-17 10:03:17

标签: .net visual-studio resources

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

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

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

有人可以澄清一下这是如何运作的吗?

2 个答案:

答案 0 :(得分:2)

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

答案 1 :(得分:0)

快速解答

添加到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()从哪里得到它?

好吧,最终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