Imagine setting the background image of a form by loading a bitmap from a file: // MainForm.cs namespace ResourcesSample { partial class MainForm : Form { public MainForm() { ... // Load azul.jpg this.BackgroundImage = new Bitmap(@"c:\windows\web\wallpaper\azul.jpg"); } } } The problem with this code is that not all installations of Windows have Azul.jpg, and even those that do have it may not have it in the same place. Even if you shipped this picture with your application, a space-conscious user may decide to remove it, causing your application to fault. The only safe way to make sure that the picture, or any file, stays with your code is to embed it and load it as a resource. Manifest ResourcesResources are added to an assembly at compile time. To embed a resource into an assembly using VS05, you must add the file to your VS05 project.[2] To add a file to a project, right-click on your project in Solution Explorer, choose Add Existing Item, and choose the file you want to add. If it's not already there, it will be copied into your project's directory. To embed the file as a resource, right-click on the file and choose Properties; then, change Build Action from Content (the default) to Embedded Resource, as shown in Figure 13.1.
Figure 13.1. Setting a File's Build Action to Embedded Resource
When a file is marked as an Embedded Resource, it becomes embedded in the assembly's set of manifest resources. The manifest of an assembly is composed of a set of metadata that describes part of the assembly. Part of that metadata is the name and data associated with each embedded resource. Naming Manifest ResourcesTo check that a file has been embedded properly into your project's output assembly, you use the .NET Framework SDK tool ildasm.exe. This tool shows all embedded resources in the Manifest view of your assembly, as shown in Figure 13.2. Figure 13.2. The ildasm Utility Showing an Embedded Manifest Resource
As shown in ildasm with the .mresource entry, embedding a file as a resource causes VS05 to name the resource using the project's default namespace, an optional subfolder name, and the resource's file name itself in the following format: defaultNamespace.folderName.fileName The default namespace portion of the resource name is the default namespace of the project itself, as set via Solution Explorer | projectName (right-click) | Properties | Application Tab | Default Namespace (see Figure 13.3). Figure 13.3. A VS05 Project's Default NamespaceIf the file happens to be in a subfolder of your project, the folder name of the resource includes a version of that folder name, replacing the backslashes with dots. For example, Figure 13.4 shows the Azul.jpg file in the foo\bar project subfolder, and Figure 13.5 shows the resulting name of the resource in ildasm. Figure 13.4. The Azul.jpg Resource in the foo\bar Project Subfolder
Figure 13.5. How VS05 Composes the Name of a Resource Located in a Project Subfolder
Loading Manifest ResourcesTo discover the resources embedded in an assembly, you enumerate the list of manifest resources, as ildasm does, by using the GetManifestResourceNames method of the System.Reflection.Assembly class:[3]
// MainForm.cs using System.Reflection; ... namespace ResourcesSample { partial class MainForm : Form { public MainForm() { ... // Get this type's assembly Assembly asm = this.GetType().Assembly; // Enumerate the assembly's manifest resources foreach( string resourceName in asm.GetManifestResourceNames() ){ MessageBox.Show(resourceName); } } } } When you know the name of a manifest resourceeither by enumerating the resources or by hard-coding the one you wantyou load it as a raw stream of bytes via the Assembly class's GetManifestResourceStream method: // MainForm.cs using System.IO; ... namespace ResourcesSample { partial class MainForm : Form { public MainForm() { ... // Get this type's assembly Assembly asm = this.GetType().Assembly; // Get the stream that holds the resource // from the "ResourcesSample.Azul.jpg" resource // NOTE1: Make sure not to close this stream, // or the Bitmap object will lose access to it // NOTE2: Also be very careful to match the case // on the resource name itself Stream stream = asm.GetManifestResourceStream("ResourcesSample.Azul.jpg"); // Load the bitmap from the stream this.BackgroundImage = new Bitmap(stream); } } } Note that the resource name passed to GetManifestResourceStream is the full, case-sensitive name of the resource, including the namespace and file name. If the resource is located in a project subfolder, remember to include the "dottified" version of the folder name as well: Stream stream = asm.GetManifestResourceStream("ResourcesSample.foo.bar.Azul.jpg"); Manifest Resource NamespacesIf you pass a System.Type object to the GetManifestResourceStream method, it uses the type's namespace as the namespace prefix portion of the embedded resource. This is especially useful because, by default, a newly generated class in VS05 is contained in the project's default namespace, allowing for an easy match between a type's namespace and the project's default namespace: // MainForm.cs namespace ResourcesSample { partial class MainForm : Form { public MainForm() { ... // Load the stream for resource "ResourcesSample.Azul.jpg" Stream stream = asm.GetManifestResourceStream(this.GetType(), "Azul.jpg"); ... } } } This namespace-specification shortcut also works for some types that can directly load files that are embedded as resources. For example, the Bitmap class can load an image from a resource, eliminating the need to get the manifest stream manually: // MainForm.cs namespace ResourcesSample { partial class MainForm : Form { public MainForm() { ... // Get this type's assembly Assembly asm = this.GetType().Assembly; // Load image from "ResourcesApp.Azul.jpg" this.BackgroundImage = new Bitmap(this.GetType(), "Azul.jpg"); } } } Figure 13.6 shows where all the parts of a manifest resource come from and how they're specified. Figure 13.6. A Summary of Manifest Resource Naming and Name ResolutionAlthough manifest resources are useful, their degree of integration with both VS05 and the type system is limited. However, manifest resources serve as the needed foundation for strongly typed resources, which address both of these issues. |