The
Basics of Resource Files in .Net 1.1
Summary
We learned
what manifest or managed resources are, stepped through what Visual Studio .Net
does with images it uses at design time and runtime, (hopefully) learned how to
use a few new utilities to work with resources and looked over some code that
uses resource file for images and strings in a few different ways.
After
making it all the way through this article and playing with the included code,
you will see that the basics of resource files in .Net are really easy to
use. At the beginning of my research for
this article I did not know too much about resource files, but after a little
reading of the documentation and some searching on the internet, it wasn’t long
before I had a directory full of useful utilities and also a couple that I
wrote myself, of course this was just the basics – next will be the advanced…
Download the Code
Contents
Introduction
What is a
resource?
A Step by
Step look at how VS.Net uses resource files
Resource
file formats in .Net
Text Format (*.txt)
Resx Format (*.resx)
Resources Format (*.resources)
Sample
Application
Embedded Resources
ResourceManager
Using ResourceFileWrapper (RW)
Introduction
The purpose
of this article is to give the reader a better understanding of some common
ways to use resource files in .Net applications. The goal of this article is to answer the
following questions:
·
What
are resources?
·
What
are resource files?
·
How
do you create resource files?
·
How
do you use resource files?
·
How
do you write code that uses resource files?
In order
to answer these questions and give the reader a better understanding of
resources in .Net version 1.1 we will walk through a small exercise with VS.Net
and really looking to see what goes on behind the scenes as well as introduce
several utility applications that will help you work with resources. Then we will go through the code of a sample
application that uses images and strings from resource files in order to see
some real code that uses resource files.
In this
article, I am not going to cover any ASP.Net or satellite assembly specific
topics, I think they would be better explained in another article.
What is
a resource?
Some where
along the line in learning .Net I am sure you learned the major parts of an
assembly: module, metadata, manifest, IL Code and resources. It is the resources part that I want to focus
on in this paper (if you want to learn more about the others I recommend Jeff
Richter’s Applied .Net Framework Programming or for even deeper
specifics you might try Serge Lidin’s Inside Microsoft .Net IL Assembler). With .Net assemblies there are two types of
resources: managed and unmanaged. Of the
two types of resources, I want to focus on the managed resources. Unmanaged resources are things like an icon
for your application to use in Windows Explorer (Richter mentions unmanaged
resource in Chapter 2, page 56 of his book).
The types
of resources we will be covering are know as “manifest resources”. The Common Language Infrastructure (CLI) : Partition
II Medatdata Section 6.2.2 Manifest Resources states:
A manifest resource is simply a named item of data
associated with an assembly. A manifest
resource is introduced using the .mresource directive, which adds the manifest
resource to the assembly manifest begun by a preceding .assembly declaration.
What the
CLI definition means, is that resources are non-executable data or objects (think
string and images) that an application uses.
Resource files are simply containers for these resources, typically in
.Net these resource files are embedded in the final assembly and kept track of
in the assembly’s manifest as .mresources entries.
Things
that you might want to keep in a resource file include such things as strings
(any text displayed to the user is a great candidate), images, icons, or audio
files. Placing these resources in a
resource file and not “hard coding” them in your applications can:
·
improve
your flexibility in future changes to any text strings in an application
·
improve
the time it would take to localize an application to another language
·
allow
resources to always be available for your application at runtime
One
alternative, that you are probably familiar with, to using resource files or “hard
coding” is to use external data files that you load at runtime. This does give you the flexibility of being
able to change the contents easily, but once your application is shipped, your
user might delete this external data file or worse not have access to the file,
leaving your application in a less than optimum state (might crash or might
just look bad depending on the situation).
A good
example of putting an image into a resource file, instead of loading it from
the file system at runtime, is a splash screen.
The purpose of a splash screen is not just branding of the application,
but it is to divert the user’s attention from the actual load time of the
application (user friendliness reasons).
If the image file (not using a resource file in this situation) that the
splash form uses on load is not there or is corrupt, then this splash screen
isn’t going to make your customers happy even before the application
starts. Now if you put your splash screen
image in a resource file or embed it in your assembly, the splash form will
always be able to load the image – leaving you with one less place for things
to go wrong on the user’s machine (ie. Production).
A Step
by Step look at how VS.Net uses resource files
In order
to better understand the simple situation of a background image on a form and
how resource files can help you out, let’s do a step by step look at how Visual
Studio .Net takes a background image and puts it in a resource file for you
(whether you know it or not).
Visual
Studio.Net uses resource files when you choose an image file to use as a background
image of a form and other similar image type displays (such as a PictureBox) by
setting the BackgroundImage property.
In order
to get a good understanding of how resource files are used, lets go through a detailed
example of setting a background image on a form and see what exactly VS.Net
does for us in the background.
1.
Start
VS.Net and create a new Windows Forms application (I will be using C#, but you
can use anything you want). Name the
solution BackgroundImageExample.
2.
In
the solution explorer double click on Form1 to view the form designer.
3.
In
the designer right-click and choose properties
4.
Find
the BackgroundImage property, click on the ellipse button and find a jpg file
to use as your background and click OK
|
|
Figure 1
5.
The form designer should now load the image
into the designer automatically, press CTRL+F5 to run the application and see
if it works
Ok so it
works, right? That was pretty easy, but
what actually happened to load that image?
In order to understand what just took place within so few easy steps, I
want to bring a few things to your attention.
First of all, notice in the property window for the BackgroundImage
(figure 1) it did not put the path to the actual file that you chose, it put
System.Drawing.Bitmap, which is the type of object being used as the background
but what about that file you chose?
Well, let’s find out where it went.
1.
On
the Project menu, click the Show All Files item
2.
Now
go to the solution explorer and you should see a plus beside Form1
|
|
Figure 2
3.
Click
on the plus sign and you will see Form1’s resource file (figure 2).
4.
Double-click
on Form1.resx and you will see the Resx editor interface (figure 3). Notice the entry $this.BackgroundImage with a
type of System.Drawing.Bitmap, this is the image you chose as your background
image.
|
|
Figure 3
In order
to verify that this is indeed your image, let’s check the resx file using
another tool.
1.
Go
to http://www.aisto.com/roeder/dotnet/
and download Resourcer for .Net (you might as well download reflector too if
you don’t already have it).
2.
Once
you have downloaded Resourcer, I suggest you extract the exe and put it (or a
shortcut to it) in your SendTo folder C:\Documents and
Settings\<yourusername>\SendTo -
this will allow you to right click in Windows Explorer and send a resource file
to Resourcer.
3.
Open
Windows Explorer (Windows Key + E), find your BackgroundImageExample project
folder.
4.
Find
the file name Form1.resx, right-click on it and choose SendTo and then choose
Resourcer (or you can open Resourcer and find the Form1.resx file yourself)
5.
Find
the resource name $this.BackgroundImage and click on it. The image should show in the bottom panel of Resourcer
(figure 4) – you might have to move the splitter to see the image better.
|
|
Figure 4
Now we
have seen how VS.Net will take a file and insert it into a resource file,
verified that it does load at runtime as well as verified that it is in the
resource file – now let’s see where it is in the exe.
Here is
were I suggest you add Ildasm.exe to your SendTo menu as well. You can find Ildasm under the C:\Program
Files\Microsoft Visual Studio .NET 2003\SDK\v1.1\Bin directory.
1.
Open
Windows Explorer and find your BackgroundImageExample solution and locate the
exe, it will either be one or two levels under a bin or debug directory
(depending on what .Net language you are using).
2.
Right
click on the exe and choose SendTo and then choose Ildasm (or open Ildasm and
find the exe yourself) (shown in figure 5 below).
|
|
Figure 5
3.
Double-click
on the MANIFEST node of the tree and you will see the text representation of
the manifest for this exe.
4.
Scroll
down the manifest and you will see and entry that looks like figure 6.
|
.mresource
public BackgroundImageExample.Form1.resources { } |
Figure 6
This shows
us the manifest resource entry for the BackgroundImageExample.Form1.resources
file, but what does that file look like?
We looked at the Form1.resx file, not Form1.resources file. Since we can’t actually see the contents of that
file in Ildasm’s UI, let’s decompile the exe and get a look at that resources
file.
Now I have
another tool for you to add to your SendTo directory to make your life better…
VS.Net Command Prompt Here, download it from http://www.larkware.com/Articles/VS.NETCommandPromptHere.html
It will
give you an .inf file, which you right click on and choose install. This utility will add another item to your
right click menu in the Windows Explorer that will open a command window with
the proper .Net paths set for the SDK tools at the directory you click on in
Windows Explorer (faster than going to the start prompt … VS.Net tools… then
finding the path via walking the directory).
Now let’s
tear that exe apart
1.
Open
windows Explorer (if you don’t still have it open) and find your
BackgroundImageExample solution and locate the exe.
2.
This
time in the left pane of the windows explorer right click on the directory the
exe is in and choose the new item VS.Net 2003 CMD Prompt Here. This will open a command window with the path
already set to the directory the exe is in (or you could go to your start
button, programs, Visual Studio 2003, Visual Studio 2003 tools, command prompt
and then walk to the directory the BackgroundImageExample.exe is in). See Figure 7 below.
|
|
Figure 7
3.
Type
the following: ildasm BackgroundImageExample.exe
/out:source.il
4.
You
should now have three new files in that directory, one of which is the
extracted BackgroundImageExample.Form1.resources that we saw was embedded in
our assembly.
5.
Right-click
on the BackgroundImageExample.Form1.resources file and SendTo and
resourcer. You will see it is basically
the same file as the Form1.Resx (figure 4) resource file was. The only difference that I see between the
two files is that the resources file size is quite a bit smaller than the resx
file, just as you would suspect since it is the compiled version of the corresponding
resx (xml) file.
So far we
have tracked down the flow of the actual image file from the setting of the
BackgrounImage property to the runtime binary, but now how does the image get
loaded from this resource file into the background of the form? Let’s look at the code:
1.
Go
back to your Solution explorer in VS.Net and double-click on Form1 and then
right click and choose View Code.
2.
Scroll
down and find the region that says “Windows Form Designer generated code” and
open that region up.
3.
If
you look at the InitializeComponent method you will see the following code (I
trimmed out some namespace info to shorten the text):
|
ResourceManager resources =
new ResourceManager(typeof(Form1)); this.BackgroundImage
= ((Image)(resources.GetObject("$this.BackgroundImage"))); |
Figure 8
The code
shown in figure 8 are the two lines that are needed to retrieve the background
image out of the resource file – at design time as well as runtime. We will see how to use the ResourceManager
class later in another example.
NOTE:
since the image file is copied into the resource file at the time you chose the
image, the background image (now a stream in the resource file or a Base64
Encoded byte array depending on how you look at it) will not reflect any
changes made to the original image file – there is NO link between the two
representations of that image. In order
to update the resource version of the file you will need to remove the
resource, compile and add the resource back, the next time you compile it
should have the new resource.
So now we
have seen that the following takes place in VS.Net when you set the
BackgroundImage property of a form.
1.
VS.Net
copies the chosen file into its resource file (resx file)
2.
VS.Net
loads that image from the resource file at design time so the form designer
will reflect the new settings
3.
When
you compile the application, VS.Net will create a .resources file and embed
that file into the final assembly
4.
The
same code that the designer used (in InitializeComponent) will also run at
runtime retrieving the image stream from the resource section of the assembly.
Resource
file formats in .Net
There are
two main formats to resource files in .Net, resx and resources. If you use the ResGen.exe utility to create a
resource file, you also have the option of using a text file. Both the text and resx file formats are sort
of an intermediate representation of the resource file before it gets compiled
into a resources file. Unfortunately, in
VS.Net 2003 there isn’t a way to add resources to a resources file in a one
step manner (although VS.Net will take care of compiling the resx file format
into a resources file for you – giving you the ability to handle strings in a
“one-step” process).
Text Format (*.txt)
As
mentioned above, you can create a text file and use it as a resource file for
your application. Of course the only
type of resource you can represent in a text file is strings and the file must
be saved in one of three encodings UTF-16 (little-endian or big-endian) or
UTF-8. All resources in the text file
need to be in the following format:
name=value
If you
need to have comments in your text file that are not to be used as a resource
you can use the ‘;’ semi-colon or ‘#’ number sign characters at the beginning
of the line to exclude it from resource creation.
Since
keeping strings in a text file and being able to use that text file in creating
resources is so useful, I added this capability to the ResourceFileCreator and
RFC utilities that we will talk about later.
Figure 9
shows an example of a text file full of name/value pairs that can be added to a
resource file.
|
|
Figure 9
As you can
see in figure 9 the text file has a comment as the first line and then five
very simple name value items. I should
mention the fact that there are no spaces in my names. Spaces are supported in resource names (after
all it is just a string key to a dictionary of resources – more or less), but
in the examples later we will be generating a wrapper class that will expose a
property (which cannot have spaces) with the same name as the resource.
There are
a couple of ways we can convert a text file to a resx format resource file:
ResGen and the RFC utility.
Using
ResGen.exe to create a Resx file
|
ResGen
C:\images\descriptions.txt C:\images\descriptions.resx |
Figure 10
Using
RFC.exe to create a Resx file
|
RFC
/f:C:\images\descriptions.txt /o:C:\images\descriptions.resx |
Figure 11
If you open
up descriptions.resx using Resourcer you will see all the name value pairs have
been added (Figure 12).
|
|
Figure 12
You could
also create a .resources file using both of these tools by just changing the
extension of the output file to be .resources instead of .resx.
How do
these utilities create the resource file?
First thing that happens is a check to see what type of resource file is
to be created (resx or resources). This
is necessary because they use different writers (ResXResourceWriter or
ResourceWriter), which we’ll learn how to use in the next couple of
sections. Other than determining which
resource writer to use, the text file needs to be parsed for name/value
pairs. The way I do it in the RFC
utility is by using the following RegEx expression: (^[^;#\s][^=]*)=([^=;#]*)\r\n
The RegEx
engine will return matches containing name/value pairs, which are then
enumerated through and written to the resource file.
ResX Format (*.resx)
Resx files
are Xml files that comply to the Microsoft ResX Schema. There are a few ways to get a resource into a
resx file that we will go through: VS.Net IDE, ResXWriter Class, ResXGen.exe,
RFC.exe (or WinResourceFileCreator.exe) or Resourcer.
Using Visual Studio .Net
VS.Net has
an item type that will add a .Resx file to your project. Project menu -> Add New Item -> Assembly
Resource File (figure 13).
|
|
Figure 13
As with
most XML file in Visual Studio, you will have two views of the data, one is the
text (think angle brackets) and the other is more of a grid view (figure 3). This grid view is nice for adding strings to
your resx file, but it will not be able to help you with adding images. In order to add other resource types you will
need to use one of the other ways of creating/editing resx files.
Using the System.Resources.ResXWriter
Class
This is
the class you would use to write a resx file (and is what is used in the other
utilities that we’ll go into next). One
thing to note about this class is that it resides in the
System.Windows.Forms.dll (the rest of the System.Resources namespace resides in
mscorlib.dll). If you look at the code
in ResourceFileCreator (part of the download)
you might notice that the adding of resources to a resource file using
ResourceWriter and ResXWriter are the same because they both implement the
IResourceWriter interface. Typically if
you are creating a resource file programmatically the process is like this:
1.
Create
a backing stream to used with the resource writer
2.
Create
the resource writer (passing the backing stream to it)
3.
Use
the AddResource() method to add resources to the writer
4.
Once
you are done adding resources, call Generate() – to make sure all resources are
added to the output stream (think Flush()).
5.
Close
the resource writer (this method will make sure the backing stream is closed as
well).
Using ResXGen
RegXGen is
a tutorial utility application that comes with the .Net SDK. It is usually installed at: C:\Program
Files\Microsoft Visual Studio .NET
2003\SDK\v1.1\Samples\Tutorials\resourcesandlocalization\resxgen
This means
if you have the SDK installed, then you have this utility and its code.
|
ResXGen
/i:c:\images\discoverypark1.jpg /n:DiscoveryPark1 /o:C:\images\images.resx |
Figure 14
ResXGen
has the following command line arguments:
|
/i: |
Input
image filename to convert |
|
/o: |
Output
.resx filename |
|
/n: |
Name of
the resource |
|
/s |
Displays
the regx schema |
Figure 15
Using RFC
This is
one of the utilities included with the source code of this article. The RFC and WinResourceFileCreator can both
be used to create resource files, but currently will not append to an existing
resource file (Resourcer is better for this).
|
RFC
/f:C:\images\discoverypark1.jpg /o:C:\images\images.resx |
Figure 16
Using Resourcer
This is by
far the easiest of the options.
Open Resourcer,
Choose New on the File Menu, choose Insert Files on the Edit menu, browse to
the image you want to add and click OK,
click the save button, choose the resource file extension you want, give
it a name, and click OK.
Resources Format (*.resources)
Resources
files are binary resource files that are usually created by VS.Net at compile
time, but can be created programmatically using the ResourceWriter class, RFC.exe,
ResGen.exe or Resourcer.
Using the System.Resources.ResourceWriter
Class
This is
the Writer class that will write a binary resource file. The process is exactly the same as the
ResXWriter (see above section titled *.resx).
Using RFC
This utility
will also create a resources file in the same manner as it creates a resx file
depending on what file extension is on the output file.
|
RFC
/f:C:\images\discoverypark1.jpg /o:C:\images\images.resources |
Figure 17
Using ResGen
Since this
utility is designed to convert from one resource format to another, you will
need to already have all the resources in a text file or a resx file, which can
be done by using one of the options above.
|
ResGen
images.resx images.resources |
Figure 18
Using Resourcer
This again
is by far the easiest of the options and is exactly the same as adding items to
a resx file (see above), just choose to save the file with a .resources
extension instead of .resx.
Sample
application
Now that
you have an idea of what resources are and how to put them in resource files as
well as the different formats of resource files, let’s look at an example. I have included a sample application in the
code for this article. There is a VB.Net
version, C# version and a Managed C++ version.
The Managed C++ version does not have the embedded image examples, only
the resource manager and resource file wrapper examples.
In order
to demonstrate some of the different ways to include resources in your assembly
as well as different manners of accessing resources at runtime, I have put
together a simple Windows Forms application that uses some photos and some text
resources. The sample application is a
simple photo album. The idea is to have
a photo and its description shown and the ability to step through the set of
photos by using previous and next buttons (figure 19).
A few
things to note about the sample application
In order
to include the different approaches to embedding images and the different code
used to access the manifest resources you will need to take the following items
into account:
·
In
order to change the manner of which resources are used/accessed you will need
to comment/uncomment the proper methods in the btnNext_Click() and btnPrevious_Click() event
handlers.
·
The sample application has both embedded
images as well as a resource file that also contains the same images.
|
|
Figure 19
Embedded Resources
One of the
options we have to include images (or any file) in a project is to include them
as embedded resources. In the sample
application I have embedded five images in the application using Visual Studio. In order to do this, all you need to do is
add the items to your project and in the properties window (Figure 20) set the
Build Action to Embedded Resource.
|
|
Figure 20
When you
add resources in this manner, they will be added at compile time to your
assembly with a resource name the same as the file name you added (with the default
namespace of the application pre-pended to the file name). For example in figure 21 you can see the
manifest (from ILDasm) that has all the embedded images listed with their names
as manifest resource (.mresource) items.
|
|
Figure 21
With
embedded images, we have two choices of retrieving our images from the assembly
manifest. In the sample code these
choices are represented in the ChangeImageUsingManifestResourceStream() and ChangeImageBitmapConstructor()
methods.
First we’ll look at the version that uses a resource stream
(figure 22). I have cleaned out the code
that deals with the string resource right now because it is not embedded in
this case (it is in the Images.resources file) – only the image file.
|
private void
ChangeImageUsingManifestResourceStream(int
intImageIndex) { Assembly
assembly = Assembly.GetExecutingAssembly(); … string strImageName = String.Format("HenleyCSharp.DiscoveryPark{0}.JPG",
intImageIndex.ToString()); System.IO.Stream
objImageStream = assembly.GetManifestResourceStream(strImageName); … _pbImage.Image = System.Drawing.Image.FromStream(objImageStream); … } |
Figure 22
Since our
resources are part of the compiled assembly we need to get a reference to the
executing assembly. Next (and very
important) we need to have the resource name in order to look up the resource
in the manifest. In this case I know the
namespace and the file name (derived from the current index of the photos) is
HenleyCSharp.DiscoveryPark1.JPG (if the current index is 1). Remember this is a photo album application, in
which the current index keeps track of which image and description to show the
user. After the resource name is derived
we can now look the resource up in the manifest. In this case we know the resource is an image
object so we need to use the GetManifestResourceStream() method to get a Stream
object back. Lucky enough for us Image
has a static (shared) method named FromStream() that takes a stream in and will
return a valid Image object.
Now let’s
look at a slightly different way of getting an image resource out of the
assembly’s manifest.
|
private void
ChangeImageBitmapConstructor(int
intImageIndex) { … string strImageName = String.Format("DiscoveryPark{0}.JPG", intImageIndex.ToString()); … _pbImage.Image = new
Bitmap(this.GetType(),
strImageName); … } |
Figure 23
In figure
23 you might have noticed that we aren’t dealing with the Assembly directly. This is due to the Bitmap constructor that
takes a Type and a string to return an image.
What the Bitmap constructor is doing behind the scenes is basically what
we did in the last example (figure 22).
You might also notice the namespace “HenleyCSharp” is not pre-pended to
the image name. The code that we have
written in figure 23 makes it look as if the Bitmap object is keeping track of
all our resources for us (which it really isn’t – the assembly is). In this example the Bitmap class is doing the
manual work of getting the image from the assembly manifest as a stream and
loading it for us.
With just
these two embedded image examples I am sure you can see some advantages to being
able to embed a file into an assembly and easily access it as a stream. The ResourceFileWrapper utility that I have
included with this code uses this technique to keep the XSLT files as resources
embedded in the assembly.
Now let’s
look at accessing resources that we put into a resource file and embedded into
our assembly (either by using VS.Net, al.exe or your compiler of choice).
ResourceManager Class
Earlier we
discussed the different formats of resource files and ways to create them, now
let’s see how we put those resource files into our assembly and how we can
access those resources once they are in our assembly by using the
ResourceManager class.
In order
to add or link a resource file to an assembly you need to already have a
.resources file (see above on how to do that).
If you have added all the resources to the resx that is in your VS.Net
project you will not need to worry about this because VS.Net will take care of
that for you.
Using
VS.Net to do it for you
Here you
have two options: 1. Use Resourcer to
add your resources to an existing resx file in your project. 2. Create
an resx file outside of your project, add all your resources to it, then add
that resx file to your project (via Add Existing Item). When you compile your application VS.Net will
take care of the rest for you.
Using
command line utilities
Here you
have two choices: 1. AL.exe 2. csc.exe or vbc.exe. I will leave this as an exercise to the
reader if they choose to dive into the manual linking. See the links provided in the Utilities
section of documentation for the compilers and the linker. You might also want to check out Chapter 2 of
Richter’s book.
Now that
we know how to add our resources to our assembly (via a resource file) we now
need to access our resources in our code, so let’s get back to the sample
application.
The method
ChangeImage is the method we want to look at
now. In the case of the sample
application I have a resources file that contains all the images and
descriptions named images.resx.
|
private void
ChangeImage(int intImageIndex) { Assembly assembly =
Assembly.GetExecutingAssembly(); ResourceManager resources = new
ResourceManager(
"HenleyCSharp.Images", assembly); string strImageName = String.Format( "DiscoveryPark{0}",
intImageIndex.ToString()); string strImageDescription = String.Format( "DiscoveryPark{0}_Description"
,intImageIndex.ToString()); _pbImage.Image = (System.Drawing.Image)resources.GetObject( strImageName); _lblDescription.Text = resources.GetString(strImageDescription); } |
Figure 24
As you can
see in figure 24 the constructor of the ResourceManager takes a string and an
assembly object. The string that we are passing
(“HenleyCSharp.Images”) is knows as the base name of the resource. You can derive this base name two ways: 1.
Add the default namespace of the project and the name of the resources file
together 2. Open up the assembly and
look for it.
If you use
the Reflector utility (see Utilities section on where to get it), you can see
the resources under the assembly much the same as we did earlier (figure 6) when
we were tracking down what VS.Net does with image resources. The advantage to using Reflector in this case
is the ease at seeing what is in that resource set called (in this case)
HenleyCSharp.Images[.resources]. (figure
25). The .resources extension is assumed
so the base name doesn’t need to include it.
|
|
Figure 25
Once we
have a ResourceManager loaded with our resource file contents we can access the
contents with their resource name. The
two methods that are used to access these resources are the GetString() and
GetObject() methods. The GetString() of
course takes in a resource name and returns the string representation of that
resource. The GetObject() method will
return an object which leaves it to us to cast that resource to the object that
we need. In the sample application it is
an Image.
Using ResourceFileWrapper (RW)
Utility
Creating a
wrapper class for your resource file using the ResourceFileWrapper and using
that wrapper class.
In order
to simplify the extraction of resources from a resource manager and to have
strongly typed access to those resources, I create what I call a resource file
wrapper. This wrapper class contains the
logic to read in the resources from the assembly and exposes each resource in
that resource set as a strongly typed property on the wrapper class. Let’s look at the images wrapper for the
sample application.
In order
to create this wrapper, I used the ResourceFileWrapper utility command line application
named RW. Once I had all the images and
the text file with the descriptions added to the resx file, the creation of
this wrapper class was easy.
|
RW
/r:C:\images\images.resx /l:cs /n:HenleyCSharp |
Figure 26
RW has the
following command line arguments:
|
/r: |
Path to
the resource file to wrap (either resx or resources) |
|
/l: |
Language
to create the wrapper in (cs, vb or cpp) |
|
/n: |
Namespace
or BaseName excluding the resource file name |
Figure 27
Currently
the resource file wrapper class is generated and saved in the same directory as
the resource file. This actually has an
unexpected benefit when using VS.Net. If
you create a wrapper class using the resx format and have a code class that has
the same name as the resx file, VS.Net will add the resource class and the code
class to your project when you add the class (via Add Exiting Item). You won’t be able to see the resx file unless
you have the show all files option turn on.
|
|
Figure 28
Figure 28
shows the interface to this new file wrapper class. Now that we have a wrapper and have it added
to the project let’s look at the code we need to access the resources.
|
private void
ChangeImageUsingWrapper(int intImageIndex) { Images imageResource =
new Images(); string strImageName = String.Format("DiscoveryPark{0}", intImageIndex.ToString()); string strImageDescription = String.Format( "DiscoveryPark{0}_Description"
,intImageIndex.ToString()); _pbImage.Image = imageResource.GetImage(strImageName); _lblDescription.Text = imageResource.GetString(strImageDescription); } |
Figure 29
All of the
resources are now available as properties on the Images object. This allows a developer to write code like:
|
_pbImage.Image
= imageResource.DiscoveryPark1; |
Figure 30
The reason
the sample code shows the use of the GetImage() method is due to the way that I
am walking through the photos using the current image index.
Summary
We
introduced what manifest or managed resources are, stepped through what Visual
Studio .Net does with images it uses at design time and runtime, (hopefully)
learned how to use a few new utilities to work with resources and looked over
some code that uses resource file for images and strings in a few different
ways.
After
making it all the way through this article and playing with the included code,
you will see that the basics of resource files in .Net are really easy to use. At the beginning of my research for this
article I did not know too much about resource files, but after a little
reading of the documentation and some searching on the internet, it wasn’t long
before I had a directory full of useful utilities and also a couple that I
wrote myself, of course this was just the basics – next will be the advanced…
Utilities
ResourceFileCreator
This is a
utility that provides similar functionality as the .Net SDK ResGen.exe utility.
http://jasonhaley.com/articles/resourcefiles/resource%20file%20creator.htm
ResourceFileWrapper
This is a
utility that can be used to generate a C# or Visual Basic.Net class that wraps
your resource file.
http://jasonhaley.com/articles/resourcefiles/resource%20wrapper.htm
.Net SDK Tools
C:\Program
Files\Microsoft Visual Studio .NET 2003\SDK\v1.1\Bin
AL.exe
Assembly
Linker - http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cptools/html/cpgrfAssemblyGenerationUtilityAlexe.asp
CSC.exe
ILDasm.exe
IL Dissembler
– http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cptools/html/cpconMSILDisassemblerIldasmexe.asp
ILAsam.exe
IL
Assembler - http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cptools/html/cpconMSILAssemblerIlasmexe.asp
ResGen.exe
Resource
File Generator - http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cptools/html/cpgrfResourceFileGeneratorUtilityResgenexe.asp
VBC.exe
Visual
Basic Compiler - http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vblr7/html/valrfVBCompilerOptionsListedAlphabetically.asp
.Net SDK Tutorials and code
C:\Program
Files\Microsoft Visual Studio .NET
2003\SDK\v1.1\Samples\Tutorials\resourcesandlocalization
ResXGen
Console
application sample utility that will generate an .resx file and add images to
it (give the path to the image).
ResDump
Console
application sample that will iterate all the resources in resource files
ResEditor
Windows
form sample that will allow you to edit a resource file
Resource Editor for .resx files
ResView
http://www.gotdotnet.com/team/clr/bcl/demos/demos/zipfiles/ResViewCS.zip
Resourcer for .Net
http://www.aisto.com/roeder/dotnet/
Reflector
http://www.aisto.com/roeder/dotnet/
Resource Editor 1.2 for VS.Net
http://weblogs.asp.net/gmilano/archive/2004/11/12/256582.aspx
Assembly Viewer
http://www.codeproject.com/dotnet/asmex.asp
VS.Net Command Prompt Here
http://www.larkware.com/Articles/VS.NETCommandPromptHere.html
Resources Consulted
Chris
Sells, Windows Forms Programming in C#, Addison Wesley, 2004
Jeffrey
Richter, Applied Microsoft .Net Framework Programming, Microsoft Press, 2002
Serge
Lidin, Inside Microosft .Net IL Assembler, Microsoft Press, 2002
Pradeep
Tapadiya, .Net Programming: a practical guide using C#, Prentice Hall
PTR, 2002
ECMA
and ISO/IEC C# and Common Language Infrastructure Standards, http://msdn.microsoft.com/net/ecma/
Shared
Source Common Language Infrastructure 1.0 Release (Codename Rotor)
Rotor
Source:
http://www.123aspx.com/rotor/default.aspx
Hyperlinked
version of documentation built with doxygen
http://dotnet.di.unipi.it/Content/sscli/docs/doxygen/fx/bcl/index.html