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

Wednesday, April 9, 2014

Visual C# projects properties manual customization - 2/3

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

Context

My recent experience with manually editing C# project description files gave me an answer to one of the oldest questions I had about the Visual C# environment: is it possible to have configuration dependent project references?

External files referencing

Coming from the C++ world and being quite experienced with the Visual C++ environment, I'm used to finely configure the static libraries I want to link to projects using the Linker property page of the project properties. I typically use it to link a project with the static library matching the current project configuration (either debug or release).
But there is no such feature in Visual C#. The only way to use code not declared in the solution itself is to reference external files, most often DLLs (from now on, I will refer to such files as "libraries"). Yet much more simple and straightforward, C# library referencing has some drawbacks compared to its C++ counterpart:
  • The list of referenced libraries is identical for all project configurations.
  • Referencing only targets actual files.
Some might argue it doesn't matter. I agree it is clearly not as harmful as in C++, where mixing debug and release code can lead to crashes. I have no idea how different might be debug and release code in .NET, but just a quick look at the Build page of the project properties shows differences, with the default settings:
  • The Optimize code option is checked only for the release configuration.
  • The Define DEBUG constant option is checked only for the debug configuration.


This is why I prefer to ensure the version of the libraries I used match my project configuration, if possible. I was wondering if this could be automated.

Project description file edition

As in my previous article [1], the answer was to come from the project description file customization.
  • I searched for my target library reference description in the project description file (.CSPROJ extension). I found it, described as a Reference element.

    <Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0"> ... <ItemGroup> <Reference Include="MyLib"> <HintPath>..\..\MyLib\MyLib\bin\Debug\MyLib.dll</HintPath> </Reference> ... </ItemGroup> ... </Project>
  • I updated its path to automatically reflect the current project configuration. This dynamic property can be accessed through the $(Configuration) variable.

    <Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0"> ... <ItemGroup> <Reference Include="MyLib"> <HintPath>..\..\MyLib\MyLib\bin\$(Configuration)\MyLib.dll</HintPath> </Reference> ... </ItemGroup> ... </Project>
  • Finally, I validated my manual modifications using the environment Object browser. It can be accessed via the main menu > View > Other Windows > Object Browser.



Technical note: I noticed dynamic property dependent values may not be correctly handled by the Properties window. As seen above, the Object browser should be trusted instead.


Conclusion

This basic sample is just a glimpse of what can be achieved through project description file customization. This feature offers much more advanced possibilities.

References

[1] Stef's dev tips 'n' tricks: Visual C# projects properties manual customization - 1/3

Saturday, March 15, 2014

Visual C# projects properties manual customization - 1/3

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

Context

I started a C# library (DLL) development for the company I'm currently working for, using their legacy .NET Framework version and tools : the outdated .NET v2.0 on Visual C# 2005. I was requested to migrate the solution to the more recent .NET v4.0 on Visual C# 2010 Express. This was very easy using the IDE integrated project migration tool, but I wanted to keep the .NET v2.0 version of the solution, and have it coexisting with the new .NET v4.0 version. Things turned out to be more complex than initialy expected...

Framework version project property

Coming from the C++ world and being quite experienced with the Visual C++ environment, I would have expected Visual C# would also offer a lot of project properties and be very flexible. I forked the default Debug and Release solution configurations into Debug_2_0 and Release_2_0 for the legacy .NET v2.0 version of the libraries. I set the current solution configuration to Debug_2_0, opened the projects properties > Application and set the Target Framework to .NET Framework 2.0.


Once the solution was rebuilt, I ensured the result actually referred to .NET v2.0. I used the dedicated Visual Studio companion tool MSIL Disassembler [1] (ildasm.exe). I could confirm my library target framework was .NET v2.0 for the Debug_2_0 configuration.


But when checking whether the Target Framework was .NET Framework 4.0 in the Debug solution configuration, I found out the property was set to .NET Framework 2.0 as well. I understood the Target Framework property was not project, but solution configuration dependent.

In the intricacies of the project description file

Although it did not answer my question, I was given a decisive clue by a StackOverflow topic [2]: I found out it was possible to bypass limitations of the GUI about project properties by editing the project description file (.CSPROJ extension). Such files are just XML files and thus can be edited manually.
  • I searched for a possible candidate for the Target Framework property. I found it : TargetFrameworkVersion.

    <Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0"> ... <PropertyGroup> <TargetFrameworkVersion>v4.0</TargetFrameworkVersion> ... </PropertyGroup> ... </Project>
  • I copied the property into the Debug_2_0 and Release_2_0 conditional property groups.

    <Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0"> ... <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release_2_0|AnyCPU'"> <TargetFrameworkVersion>v4.0</TargetFrameworkVersion> ... </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug_2_0|AnyCPU'"> <TargetFrameworkVersion>v4.0</TargetFrameworkVersion> ... </PropertyGroup> ... </Project>
  • I set the copied tags value to v2.0.

    <Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0"> ... <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release_2_0|AnyCPU'"> <TargetFrameworkVersion>v2.0</TargetFrameworkVersion> ... </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug_2_0|AnyCPU'"> <TargetFrameworkVersion>v2.0</TargetFrameworkVersion> ... </PropertyGroup> ... </Project>
  • Finally, I validated my manual modifications using the MSIL Disassembler.



Conclusion

Despite I was a little disappointed to meet limitations in the Visual C# GUI for such basic needs as per project .NET framework version customization, learning how to bypass them was very beneficial. Then, I did not know I was about to make a much more advanced use of it.

References

[1] Microsoft Developer Network (MSDN): Ildasm.exe (IL Disassembler)
[2] Stackoverflow: question 8161183 - visual studio 2010 compiler conditions based on target framework