One more time about Resource vs. EmbeddedResource

In Visual Studio you can set “Build Action” for a project item to ‘Resource’ or ‘Embedded Resource’, among other things. The difference between the two is confusing, and exact up-to-date documentation is hard to find. (This StackOverflow post is probably the best, but not 100% accurate.) Today I became confused one more time, so I decided to clear up the matter and put an end to the confusion.

First of all, both kinds of resource are actually embedded in the executable. ‘EmbeddedResource’ files are placed directly into the executable as manifest resources. All ‘Resource’ files are put in a special structured manifest resource named ‘ProjectName.g.Resources‘.

Embedded Resources

Embedded resources are the same as manifest resources. You can see them as .mresource records in ILDASM. If in a project named MyProject you create a file named Texts\Guide.txt and mark it as EmbeddedResource, the project output will have a manifest resource named MyProject.Texts.Guide.txt.

Embedded resources can be enumerated by calling Assembly.GetManifestResourceNames() and read via Assembly.GetManifestResourceStream().

Resx files

Embedded resource has no predefined structure: it is just a named blob of bytes. So called “.resx” file is a special kind of embedded resource. It is a string-to-object dictionary that maps a name to an object. The object may be a string, an image, an icon, or a blob of bytes. Resx files can be used for localization: in addition to the name each object may have a culture, e.g. “Neutral”, or “English (UK)”.

You can add resx file to your project by right clicking on the project name, choosing Add->New Item... and then selecting Visual C# Items->General->Resource file. The entire resx file is placed into the executable as a single manifest resource. In the name of the manifest resource “.resx” extension is replaced with “.resources“.

Resx files are accessed via the System.Resources.ResourceManager class. Note that the “base name” supplied to the constructor is the file name without extension. You can retrieve a particular resource by calling ResourceManager.GetString(), ResourceManager.GetObject(), or ResourceManager.GetStream(). You can get an entire dictionary for a particular culture via ResourceManager.GetResourceSet().

Resource Build Action

Files marked with build action of “Resource” are added to a special resx file called ProjectName.g.resx. This file is generated during the build, it is not part of the project. You can access content of the ‘Resource’ files by creating an instance of ResourceManager and calling GetStream(filename). Additionally, in WPF applications you can access these resources via Application.GetResourceStream() in C# and via things like <Image Source="filepath" /> in XAML.

Project resources

When you edit project resources on the Resources tab of the project property pages, Visual Studio creates another special resx file named Properties\Resources.resx. Corresponding manifest resource name is ProjectName.Properties.Resources.resources (yes, “resources” is repeated twice, one comes from the file name, and the other from the “.resx” extension being replaced with “.resources”). Visual Studio also creates a file called Resources.Designer.cs that contains code for easy access to the dictionary items. E.g. a string named “WindowHeader” may be accessed simply as Properties.Resource.WindowHeader, which will call ResourceManager behind the scenes.

Putting it all together

A sample program (ResourceTypes.zip) demonstrates different kinds of resources and how to access them.

It has

  • One file with build action EmbeddedResource named EmbeddedResourceFile.txt
  • Two files with BuildAction ‘Resource’ named ResourceFile.txt and ResourceFile2.txt
  • Standard project resx file Properties\Resources.resx with some key-value pairs.

The output shows that there are three manifest resources, one of which is a simple file, and two others are resx resources with additional internal structure:

Manifest resources
        ResourceTypes.g.resources:
                '???☺   ?   lSystem.Resources.ResourceRea...'
        ResourceTypes.Properties.Resources.resources:
                '???☺   ?   lSystem.Resources.ResourceRea...'
        ResourceTypes.EmbeddedResourceFile.txt:
                'EmbeddedResourceFile.txt: it is compiled...'

Items in ResourceTypes.g:
        resourcefile2.txt: Stream: ResourceFile2.txt: it is compiled as 'Re...
        resourcefile.txt: Stream: ResourceFile.txt: it is compiled as 'Res...

Items in ResourceTypes.Properties.Resources:
        MyKey: MyValue
        Key2: Value2

Conclusion

It would not hurt if the names were less confusing and the documentation were clearer and easier to find. Yet, the “resources” topic has a pretty long history, so I guess this is the best we could get for the money.

9 Comments



  1. Thank you for taking the time to do this.
    I am a very experienced programmer but you still educated me on a few points and solved an issue that was mystifying me.

    Reply

  2. Thanks for the interesting info, I wish I had found this earlier.

    There are two ways you can produce the manifest resource (.g.resources)

    1) MSBuild my.csproj /t:PrepareResources
    The PrepareResources target is made available as the csproj includes Microsoft.CSharp.targets. When you run this command it will stop a bitbefore the Compile step, before any .cs file is actually processed.
    It will, as indicated in TFA, produce a “Assemblyname.g.resources” in $(IntermediateOutputPath)/obj/

    The second way to produce a manifest resource is by creating a blank .resx XML file and calling ResGen directly. However, it won’t be possible to add it the the usual way through the IDE property sheet.
    A minimalist one would look like this (sorry, please copy/paste and unescape yourself):

    (root)
    (resheader name=”resmimetype”)text/microsoft-resx(/resheader)
    (resheader name=”reader”)(value)System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089(/value)(/resheader)
    (resheader name=”writer”)(value)System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089(/value)(/resheader)
    (data name=”my_entry.jpg” type=”System.Resources.ResXFileRef, System.IO”)
    (value)my_entry.jpg;System.IO.MemoryStream, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089(/value)
    (/data)
    (/root)

    Notice how the regular value element

    image.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a

    is being replaced with a stream

    image.jpg;System.IO.MemoryStream, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089

    2) You can then compile the file like this:
    ResGen /compile Myresource.resx,Assemblyname.g.resources

    Or if your file is already properly named
    ResGen Assemblyname.g.resx

    where Assemblyname needs to match the dll it will be linked to later

    Reply

    1. Infosix, thank you for the info! I am wondering, however, when employing the low level tools gives you more benefit than just adding resources in the IDE? Like, automatically generating projects, or automating addition of large number of resources? The reason I wrote this article was that I kept forgetting the difference between “resource” and “embedded resource” when specifying “Build action” in the IDE…

      Reply

  3. I don’t really know, I could see it having benefits for ISVs who don’t want to completely rely on MSBuild in their build process but just specific programs from the SDK (IDEs like Resharper, or MonoDevelop?)

    Nothing that grand for me though 😉
    The generated binary resource was used to produce a (class library) .dll for consumption in a PowerShell script of all places:

    Instantiate a compiler option object then compile (Roslyn) using the Add-Type cmdlet.

    $cp = [System.CodeDom.Compiler.CompilerParameters]::new()
    [void]$cp.EmbeddedResources.Add(“E:\AssemblyName.g.resources”)
    $cp.OutputAssembly = “E:\AssemblyName.dll”

    Add-Type -TypeDefinition “namespace a { public abstract class symbol {} }” -CompilerParameters $cp

    We need to set the output assembly dll instead of relying on Add-Type generating a random name, because it needs to match the added manifest name.

    Using it now in WPF:

    Add-Type -Assembly PresentationCore
    $script:splash = New-Object System.Windows.SplashScreen -Args @([a.symbol].Assembly, “my_image.jpg”)
    $script:splash.Show($false, $true)
    # …

    It wouldn’t work if inserted as “embedded resource”, so…

    Reply


Leave a Reply to Infosix Cancel reply

Your email address will not be published. Required fields are marked *