Runtime Embedded Resource Manager






4.50/5 (2 votes)
Jan 1, 2006
5 min read

70742

659
A library to help use your project's embedded resources at run-time.
Introduction
When you're organizing your development solution, you can go one of two routes with your non-source files: you can leave your resources external to your executable "loose" on the local file system, or you can compile them into the assembly. The first route allows you to modify the resources easily without having to redistribute code changes, but the second offers a small amount of protection against the modification of those resources, and leads to a tidier distribution.
This article isn't meant to convince you to embed if you don't have the need, but to offer some small help if you do. Reading embedded resources involves tedious and repetitive code, lending itself well to encapsulation in a library. I'll show you how and why I wrote a run-time embedded resource manager to give simplified access to images and sounds in my applications.
Background
Basically, I did this because I grew tired of writing this type of code over and over:
pictureBox1.Image =
new Icon(Assembly.GetExecutingAssembly().GetManifestResourceStream(
"RuntimeResManTest.Icons.CDROM01.ICO")).ToBitmap();
I would inevitably get the case of a character in the name of the resource wrong and waste time troubleshooting the namespace name, class name, folder name, and resource name. To further cut down on the code to read the resource, I'd inevitably cache the current Assembly
, and reference it on subsequent resource reads.
Eventually, I realized that what I wanted was a single point of contact for getting a handle to embedded resources, which in my case were always images (BMP, GIF, PNG and JPG), icons (ICO), and sound (WAV) files.
The Code
I wrote a simple class called Resources
to act as that single point of contact for instantiation and resource reading. You have to pass the assembly with the embedded resources into the lone constructor, so it can enumerate and categorize them, but that's the only configuration it needs. That parameter will ordinarily be the assembly of the executable that references the library.
private RuntimeResMan.Resources _r =
new Resources(Assembly.GetExecutingAssembly());
The constructor of the Resources
class passes the supplied Assembly
into the internal
constructors of the objects that hold the actual resource data:
Bitmaps
Icons
Sounds
These resource collection classes are structured similarly. They contain an ArrayList
object that stores BitmapEx
, IconEx
, and Sound
objects, respectively. I created BitmapEx
, IconEx
, and Sound
objects to attach a string Name
property to the resource data, for accessing the resource at run-time.
When constructed and passed an Assembly
, the Bitmaps
object reads the list of embedded resources:
internal Bitmaps(System.Reflection.Assembly target) {
foreach(string resource in target.GetManifestResourceNames()) {
string ext = Path.GetExtension(resource).ToLower();
if (ext == ".bmp" ||
ext == ".gif" ||
ext == ".jpg" ||
ext == ".jpeg")
_bitmaps.Add(new BitmapEx(resource,
(Bitmap)Bitmap.FromStream(
target.GetManifestResourceStream(resource))));
}
}
The BitmapEx
constructor takes a string with the fully qualified name of the discovered resource, and the Bitmap
object that it defines.
public BitmapEx(string name, Bitmap bitmap) {
string[] tokens = name.Split('.');
_name = tokens[tokens.Length - 2].ToLower();
_bitmap = bitmap;
}
The unqualified name of the resource is calculated and forced to lowercase, so you won't be tripped up by case when trying to use the Bitmap
later at runtime. The extension is chopped too, since it isn't necessary. The framework knows which "flavour" the Bitmap
is (GIF, JPG, etc.), so we can drop the extra characters for brevity and simplicity. This assumption would cause a problem if you have multiple resources with the same name that differ by extension (balloon.bmp and balloon.gif in the same assembly), so feel free to append the extension to the name if it suits your purpose.
My Bitmaps
class exposes the actual Bitmap
object to client code via a string
accessed indexer property (the simple name of the embedded resource), so the BitmapEx
class is never actually required to be exposed. It stays private
in the assembly.
The Icons
class works the same way, except that it searches for embedded resources with the extension ".ico", of course. In all other ways, though, it is structured and behaves the same way as the Bitmaps
class.
The Sounds
class works slightly differently. First, since there is no Sound
class in v1.1 of the framework, there's no need to use a contrived name like SoundEx
to describe an object that contains both the sound data and the name of the sound. Secondly, since this class exposes a method, Play
, to start playing the sound described, the class has to be public
. The sound data contained in the .wav file isn't really meaningful outside of the context of the parameter for P/Invoke, so the raw data isn't exposed in the same way as the BitmapEx
class exposes a Bitmap
object, or the IconEx
class exposes an Icon
.
Knowing all this, you can now use embedded resources in your projects easily, without having to muck around with reading stream
objects. You can see the simple code in the sample project.
private void cmdShowIcon_Click(object sender, System.EventArgs e) {
pictureBox1.Image = _r.Icons["cdrom01"].ToBitmap();
}
private void cmdShowBitmap_Click(object sender, System.EventArgs e) {
pictureBox1.Image = _r.Bitmaps["beany"];
}
To play a sound, add a .wav file to your project as an embedded resource and play it like this:
Sound s = _r.Sounds["burp"];
if (s != null)
s.Play();
Or, if you fear no NullReferenceException
, you can play it even more simply:
_r.Sounds["burp"].Play();
No muss, no fuss.
Caveat
This method is not very memory efficient if you have an awful lot of embedded resources and they're used infrequently in your solution. You wouldn't want to load them all aggressively at project startup, only to have them soaking up memory unnecessarily. You could modify this solution easily to load them only the first time they're required, thus spreading out the memory hit (and the overhead of the discovery process) over the lifetime of your application, rather than incurring the performance penalty up front, but I wanted to keep this example simple.
Obviously, since you're fetching and reading the same copy of the Bitmap
s and Icon
s that were read at instantiation, if you fiddle with them programmatically, all subsequent uses of the embedded resources will get the modified, in-memory versions.
Conclusion
This article wasn't meant as a tutorial on the PlaySound
API call, as much fun as it is to play with that particular function. There are a lot of other things you can do with it, like play synchronously, or stop the sound, but you can read more about those capabilities here, and add them to your solution if you're so inclined.
I really like the fact that managing resources this way insulates me from the annoying idiosyncrasies of the framework, like the fact that creating a Bitmap
from a stream
requires me to call a static
method of the Bitmap
class, while creating an Icon
from a stream
more naturally requires me to put the stream
into the Icon
constructor. Why the difference?
History
- Jan 1 2006 - Initial revision (Happy New Year).