Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Where are embedded resources stored in a .NET app?

If I add resources to Resources.resx, are they are embedded within the executable?

I have read somewhere that resources are stored within the assembly, but are all files in the project (including files in the output folder) part of the assembly?

Or, is the assembly just files and modules produced by compiler and resources aren't included in the assembly?

Can somebody clarify exactly how this works?

like image 576
Miria Avatar asked Apr 17 '11 10:04

Miria


2 Answers

The quick answer

The resources you add to a C# program are stored in the resources section of the PE binary.

For example, if I add a string, MyTestString, with the value "Charles is Cool"

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

If I open up the compiled binary in a hex editor, I can see my string:

A screenshot from a hex editor

Cool, but how did it get here?

The C# side

The resource editor generates Resources.Designer.cs, here's what it generated

/// <summary>
///   Looks up a localized string similar to Charles is Cool.
/// </summary>
internal static string MyTestString {
    get {
        return ResourceManager.GetString("MyTestString", resourceCulture);
    }
}

But wait... I don't see "Charles is Cool" anywhere in here... where did it go? Where is GetString() getting it from?

Well eventually it grovels for the resource (MSFT's terminology, not mine), I suppose we should consider this a ManifestBasedResourceGroveler, which eventually gets us to extern GetResource(), a sure sign that we've fallen off the edge of the .NET universe... you know that that means...

The CoreCLR Side

We can look at the coreclr repository for an example of how this is implemented,

If you were to trace the code here you eventually come to 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));
}

Which basically finds the offset from the PE header (see IMAGE_COR20_HEADER). Check out the Portable Executable article on Wikipedia, you will see that the svg image has a section for ResourceTable (RVA, aka Relative Virtual Address)

What I'm getting at here is, Resources aren't by any means a C# or .NET feature, they're just a managed API into something the PE binary format always had.

For arbitrary binary resources

Note that everything I said works for arbitrary data, if you were to add some binary file to your resources, Resources would present it to you as a byte[] but really it would encode it as something else.

While opening up the resx file in Visual Studio gives you a rather uninteresting path to the binary file that you imported, note that if you open up the compiled binary in something like JetBrains DotPeek and look at the resx file, the path to the file has been replaced with a string,

<data name="binary" type="System.Byte[], mscorlib">
    <value>CGdTCb7vyv7AD/6rze8=</value>
</data>

While I was not able to find any code on the Visual Studio side to prove it, I would guess this string is a base64 encoded version of the bytes in the (binary) resource file because running Convert.ToBase64String(Resources.binary) gives me the same string that's found in the compiled binary's resx file. For those of you who want to try this at home my binary file just contained 08 67 53 09 BE EF CA FE C0 0F FE AB CD EF.

like image 66
jrh Avatar answered Nov 15 '22 08:11

jrh


The embedded resources are stored inside the DLL or EXE files.

like image 27
David Heffernan Avatar answered Nov 15 '22 10:11

David Heffernan