Introduction
Time and again questions have come up in the C# and .NET forums relating to
the use of embedded resources in VS.NET. For most projects there are
no problems, but as you get into more complicated projects this quickly
becomes a problem. This article will attempt to put the information needed
in a more permanent place, making it easier to find and link to.
First things first
There are a couple different ways resources can be used in VS.NET. The
most common way is how the Form
stores the resources it uses, this is done by
creating a .resx file containing all of the resources for the Form
. This
article will not cover these files because the developer generally doesn't need
to worry about them, instead the various designers will interact with them
writing most of the needed code to use them.
The second way to use resources, and the one this article will focus on,
relies on adding the file to the project and setting the file's "Build Type"
property to "Embedded Resource". This is only the first step though!
What's in a name?
When you embed a resources as I outlined above you will typically need to
know its name. This can be as little as the filename, but usually it is
more than that.
The name is made up of three parts: <default namespace.><extended
namespace.><filename>
The first and last parts are easy to identify; the default namespace is set
in the project's properties and the filename is...well, the filename of the
file. The middle part is where most people get lost.
Quickly put, the extended namespace is made up of directory structure of the
project itself. If you place the file in the root of the project, then
there is no extended namespace and the name of the file as an embedded resource
is <default namespace.><filename>
. But it is possible to create folders
with in your project, this is where the extended namespace comes into play.
If you create a folder called Images, and place the file there, then the name of
the resource becomes <default namespace.>Images.<filename>
. If you create
another folder under Images called FormGraphics then the name becomes <default
namespace.>Images.FormGraphics.<filename>
.
See the pattern? You can use this for your code as well. When you
create a class in the root of the project the namespace is automatically
generated for you, the namespace follows the same pattern: <default
namespace><.extended namespace>
Once the code has been generated you are,
of course, free to change this namespace to whatever you want; but you need to
keep this in mind, but you can't cannot change the extended namespace used to
name an embedded resource.
Getting the resources
Universal access
The standard way to access an embedded resource is to use the Assembly
class's GetManifestResource
*
methods. In the first demo application we
will use the GetManifestResourceNames
and GetManifestResourceStream
methods.
The purpose of this demo application will be to list the resources in an
assembly, and be able to save selected resources out to a file. An added
feature will let us view the contents of a particular resource if it is an
image. If you don't have any assemblies with embedded resources handy, the
second demo application has one embedded in it which you can use.
The interesting code happens inside of the ListBox's
SelectedIndexChanged
event
System.IO.Stream stream = loadedAssembly.GetManifestResourceStream(
(string) resources.SelectedItem);
System.Drawing.Image img = Image.FromStream(stream);
The demo application loads an assembly and stores a reference to the
Assembly
in the loadedAssembly
variable. In your
applications you probably don't want to get resources from an external assembly,
you want resources from the assembly your class is defined in.
The easiest way to get a reference to the Assembly object for a particular
class is to use the Type
class' Assembly
property.
You can get the Type
by using typeof(<class>)
or if
you have an instance of the class, use its GetType()
method
(inherited from System.Object
, the root of all types in .NET).
With this technique you can use any resource embedded in an Assembly
,
you just need to know the name of the resource.
There is another way
There are actually two overloads of the GetManifestResourceStream
function, one which takes the name of the resource to get a Stream
for. The other takes a Type
and a string
.
This one helps to simplify getting the name to use for the resource. It
takes the Namespace from the Type
and appends the string passed in
(with a "." between them as well) to form the name.
A few classes in the .NET framework use this pattern as well, but instead of
returning Stream
objects they construct the particular object.
The Bitmap
class is one of these; it has a constructor with the
same pattern, and can be used to load an embedded resource into a Bitmap
object.
Another one is the ToolboxBitmapAttribute
class, which VS.NET
uses to get a bitmap to display in the toolbox for controls/components. At
runtime VS.NET will take the values stored by the attribute to retrieve the
Bitmap
embedded in the assembly. Attributes are beyond the
scope of this article, but I have written
an article
that focuses on them.
The second demo uses the second method to display a bitmap embedded in its
own assembly.
Aside from placing the controls on the Form
, there was only one line of code
I added.
picture.Image = new Bitmap(typeof(Form1), "demo1.gif");
This tells the Bitmap
constructor to find the resource named using the
namespace from Form1
(since Form1
is at the root of the project, and I didn't
change its namespace it has the default namespace assigned to it). Then it
appends a ".", then the string value passed in. In this case I just added
the image to the root of the project and set its Build Type to "Embedded
Resource".
See? That wasn't so bad :-)
Conclusion
Once you get the hang of it, using embedded resources in your .NET
applications is easy. The only hard part is figuring out the name that
VS.NET gives to your resources
Updates
- October 25, 2002 - Initial posting