Sunday, July 13, 2014

Embedded resources loading

Programming language : C#
Topic category : Language
OS : Windows
IDE : Visual C# 2010 Express

Context

I recently found myself in the basic need of loading some resources embedded in the application I'm currently developing binary. I expected such a basic operation to be a piece of cake, but it turned out it took me more than one hour to get it working.

What are resources?

Basically, resources are collections of data of nearly any type (strings, images, audio files, ...) which are stored alltogether, and can be either embedded within an application binary (executable, DLL, ...) or stored in a companion file. Their typical usage is data storage and application localization. More details can be found in the official description [1].
I personally prefer to embed my applications resources in the binaries rather than shipping them along as raw files, for many reasons: I thus ensure they can be neither altered, removed, nor reused (it seems that last point can be easily circumvented though [2]).

Loading embedded resources: a simple operation yet hard to implement

I was using resources the simplest way: since I had no localization constraints and I was developing a simple application, I obviously chose to gather all my resources into a single file, and to embed them into the generated binaries at build time. That's why I expected loading them would be very straightforward as it can be in C/C++ using system functions such as LoadString() [3] or LoadBitmap() [4]. Surprisingly, it turned out it was not the case.

Searches quickly pointed me towards the ResourceManager class [5] and especially its (String, Assembly) constructor [6], but the parameters description was helpless.
I found out Assembly assembly had to be set to Assembly.GetExecutingAssembly(), but I had no clue what value String baseName was expecting. My various attempts all ended up with the application raising a MissingManifestResourceException exception, message "Could not find any resources appropriate for the specified culture or the neutral culture. Make sure "<resource file>.resources" was correctly embedded or linked into assembly "<application>" at compile time, or that all the satellite assemblies required are loadable and fully signed.".


I especially was puzzled by the fact the message was mentioning a .RESOURCES file. I had never heard of such a format before, since the IDE was storing my resources into a .RESX file.

Digging up the intermediate files

I was given not the solution itself but a decisive clue by a very well documented article about resources [7]. I understood from the first figure (Figure 7-20) the IDE was actually transforming .RESX files into .RESOURCES ones at build time.
  • Since the file was generated at build time, I expected it to be stored with others intermediate files. I did find it there, in the obj\<Project platform>\<Project configuration> project subdirectory.


    Note: two .RESOURCES files can be seen in the picture above. The first one belongs to the application only form, since the IDE automatically provides a .RESX file for every generated form. Spotting form-related .RESOURCES files is easy, since each of them includes the form name ((Name) property) into its.
  • As specified in the ResourceManager constructor description [7], I set the baseName parameter to the .RESOURCES file name, without its extension.

    ... ResourceManager oResMngr = new ResourceManager( "MyApp.Properties.Resources" Assembly.GetExecutingAssembly() ); ... Text = oResMngr.GetString("Title"); BackgroundImage = oResMngr.GetObject("ThumbsUp") as Image; BackgroundImageLayout = ImageLayout.Center; ...
And voilà, I was finally able to load my application embedded resources.

Conclusion

It is just too bad so much effort had to be spent for such a simple task as loading embedded resources. With just a short example, Microsoft could have saved developers quite a lot of time.

References

[1] Microsoft Developer Network (MSDN): Resources in Desktop Apps
[2] NirSoft ResourcesExtract
[3] Microsoft Developer Network (MSDN): The LoadString() function
[4] Microsoft Developer Network (MSDN): The LoadBitmap() function
[5] Microsoft Developer Network (MSDN): The ResourceManager class
[6] Microsoft Developer Network (MSDN): ResourceManager Constructor (String, Assembly)
[7] Core C# and .NET by Stephen C. Perry excerpt: Using Resources