Resource Basics


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 Resources

Resources 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.

[2] The .NET Framework SDK command line compilers, such as csc.exe and vbc.exe, provide options for bundling files into assemblies as resources (for csc.exe and vbc.exe, the switch is /resource). In addition, the /embedresource switch for al.exe creates a new assembly from an existing assembly and a set of files to embed as resources.

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 Resources

To 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 Namespace


If 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 Resources

To 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]

[3] You can retrieve a type's assembly via the associated Type object's Assembly property. Similarly, the Assembly class itself provides several methods for retrieving assemblies of interest: GetAssembly, GetCallingAssembly, GetEntryAssembly, and GetExecutingAssembly.

// 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 Namespaces

If 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 Resolution


Although 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.




Windows Forms 2.0 Programming
Windows Forms 2.0 Programming (Microsoft .NET Development Series)
ISBN: 0321267966
EAN: 2147483647
Year: 2006
Pages: 216

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net