Have a question? ask www.kenlet.com
Home  |  FAQ  |  About  |  Contact  |  View Source   
 
SEARCH:
 
BROWSE:
    My Hood
Edit My Info
View Events
Read Tutorials
Training Modules
View Presentations
Download Tools
Scan News
Get Jobs
Message Forums
School Forums
Member Directory
   
CONTRIBUTE:
    Sign me up!
Post an Event
Submit Tutorials
Upload Tools
Link News
Post Jobs
   
   
Home >  Tutorials >  C# >  Embedding and Using Resources in C#
Add to MyHood
   Embedding and Using Resources in C#   [ printer friendly ]
Stats
  Rating: 4.06 out of 5 by 16 users
  Submitted: 11/19/01
John Gallardo ()

 
One of the benefits that C# and the .NET framework give to developers is the metadata contained within the assemblies. This metadata contains all information about the assembly which is not specific instructions.

This method allows developers easily embed resource "files" into the assembly, and access these resources at runtime through reflection. This is incredibly useful for embedding things such as help files, bitmaps, and windows metafiles. The key advantage to this system, is that these "files" are then carried within the executable file. You don't have to worry about a user accidently deleting or modifying the file, and thus breaking your code. This does, however, cause a signifigant increase to the size of your executable. As such, huge bitmaps or video files are probably not the best choices to use as embedded resources.

In this tutorial, I will be showing how to embed bitmaps into the assembly's metadata, and then attach a stream to that resource in order to open it as a bitmap. We will be creating a program which loads all bitmaps which are embedded resources, and display a randomly chosen one when the user clicks a button.

To begin, we open VS.NET and create a new C# Windows Application.

The next step is to add the files you want as a resource to the project. To do this you right click on the project name, and select "Add Existing Items." This will bring up a dialog where you can select the files to add. This will cause VS.NET to copy the file into your project's directory if it is not already there. This file is now part of the project you previously created.


Now we need to tell VS.NET how to handle the file or files we have just added. We do this by changing the "Build Action" for the file. Clicking on the dropdown list for Build Action, we see there are four choices: None, Compile, Content, and Embedded Resource. We will be selecting Embedded Resource. This will instruct VS.NET to tell the C#-Compiler to add the file into the metadata section of the assembly.


Now lets modify our code so as to load the bitmaps into an ArrayList.
        private void Form1_Load(object sender, System.EventArgs e)
        {            
            Stream imgStream = null;
            Bitmap bmp = null;            

            // get a reference to the current assembly
            Assembly a = Assembly.GetExecutingAssembly();
        
            // get a list of resource names from the manifest
            string [] resNames = a.GetManifestResourceNames();

            // populate the textbox with information about our resources
            // also look for images and put them in our arraylist
            txtInfo.Clear();
            
            txtInfo.Text += String.Format("Found {0} resources\r\n", resNames.Length);
            txtInfo.Text += "----------\r\n";
            foreach(string s in resNames)
            {
                txtInfo.Text += s + "\r\n";
                if(s.EndsWith(".bmp"))
                {
                    // attach to stream to the resource in the manifest
                    imgStream = a.GetManifestResourceStream(s);
                    if( !(null==imgStream) )
                    {                    
                        // create a new bitmap from this stream and 
                        // add it to the arraylist
                        bmp = Bitmap.FromStream( imgStream ) as Bitmap;
                        if( !(null==bmp) )
                        {
                            pics.Add( bmp );
                        }
                        bmp = null;
                        imgStream.Close();
                        imgStream = null;
                    }
                }
            }            
            txtInfo.Text += "----------\r\n";
            txtInfo.Text += String.Format("Found {0} Bitmaps\r\n",
                pics.Count);                        
        }


As you can see we use the Assembly object to access our embedded resources. One signifigant thing about this, is we actually have the ability to pull embedded resources from any assembly we can load, from our executing assembly assembly.

We then use the Assembly.GetManifiestResourceNames() function, which returns a string []. This is an array containing the names off all resources in the assembly.

So now is a good time to discuss how the embedded resources get their names. The resources are named using the following convention: <Namespace>.<Filename>. So if we embed a file named mybmp.bmp into our project in the MyNS namespace, we have a resource in the manifest named MyNS.mybmp.bmp. Examining the assembly using ildasm.exe will also allow you to see the names of the resources.


We then loop through all of the names of our resources, looking for one which ends with ".bmp". When we find it, we use the Assembly.GetManifestResourceStream() method to open a stream to this resource. This method takes the name of the resource as a parameter. This is almost identical to the way that a file is opened. This is a major strength of embedded resources. From a developer's perspective, it is just like working with a file once you have a stream opened on it.

Then, the Bitmap.FromStream() method is used to create a bitmap from the stream to the embedded resource. We can then add this Bitmap to our arraylist for use later.

So now you know how to embed and use resources in C#. You have seen how the resource is stored in the metadata of the assembly, which allows for easy access to the data at runtime through the Assembly.GetManifestResourceStream() method.

Here is a screenshot and the code for our complete program:


using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Reflection;
using System.IO;
using System.Diagnostics;

namespace ResourceDemo
{
    /// <summary>
    /// Summary description for Form1.
    /// </summary>
    public class Form1 : System.Windows.Forms.Form
    {        
        ArrayList pics;
        private System.Windows.Forms.GroupBox groupBox1;
        private System.Windows.Forms.PictureBox pBox;
        private System.Windows.Forms.Button btnDisplay;
        private System.Windows.Forms.TextBox txtInfo;
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.Container components = null;

        public Form1()
        {
            //
            // Required for Windows Form Designer support
            //
            InitializeComponent();

            // Instantiate our ArrayList
            pics = new ArrayList();
        }

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        protected override void Dispose( bool disposing )
        {
            if( disposing )
            {
                if (components != null) 
                {
                    components.Dispose();
                }
            }
            base.Dispose( disposing );
        }

        #region Windows Form Designer generated code
        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.pBox = new System.Windows.Forms.PictureBox();
            this.groupBox1 = new System.Windows.Forms.GroupBox();
            this.btnDisplay = new System.Windows.Forms.Button();
            this.txtInfo = new System.Windows.Forms.TextBox();
            this.groupBox1.SuspendLayout();
            this.SuspendLayout();
            // 
            // pBox
            // 
            this.pBox.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
            this.pBox.Location = new System.Drawing.Point(8, 8);
            this.pBox.Name = "pBox";
            this.pBox.Size = new System.Drawing.Size(264, 272);
            this.pBox.TabIndex = 0;
            this.pBox.TabStop = false;
            this.pBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage;
            // 
            // groupBox1
            // 
            this.groupBox1.Controls.AddRange(new System.Windows.Forms.Control[] {
                                                                                    this.txtInfo,
                                                                                    this.btnDisplay});
            this.groupBox1.Location = new System.Drawing.Point(288, 8);
            this.groupBox1.Name = "groupBox1";
            this.groupBox1.Size = new System.Drawing.Size(192, 264);
            this.groupBox1.TabIndex = 1;
            this.groupBox1.TabStop = false;
            // 
            // btnDisplay
            // 
            this.btnDisplay.Location = new System.Drawing.Point(48, 24);
            this.btnDisplay.Name = "btnDisplay";
            this.btnDisplay.Size = new System.Drawing.Size(96, 23);
            this.btnDisplay.TabIndex = 0;
            this.btnDisplay.Text = "Display Picture";
            this.btnDisplay.Click += new System.EventHandler(this.button1_Click);
            // 
            // txtInfo
            // 
            this.txtInfo.Location = new System.Drawing.Point(8, 56);
            this.txtInfo.Multiline = true;
            this.txtInfo.Name = "txtInfo";
            this.txtInfo.ReadOnly = true;
            this.txtInfo.Size = new System.Drawing.Size(176, 200);
            this.txtInfo.TabIndex = 2;
            this.txtInfo.Text = "txtInfo";
            // 
            // Form1
            // 
            this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
            this.ClientSize = new System.Drawing.Size(496, 293);
            this.Controls.AddRange(new System.Windows.Forms.Control[] {
                                                                          this.groupBox1,
                                                                          this.pBox});
            this.Name = "Form1";
            this.Text = "Form1";
            this.Load += new System.EventHandler(this.Form1_Load);
            this.groupBox1.ResumeLayout(false);
            this.ResumeLayout(false);

        }
        #endregion

        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main() 
        {
            Application.Run(new Form1());
        }

        private void button1_Click(object sender, System.EventArgs e)
        {
            // go to a random picture in our arraylist and
            // display it
            Random generator = new Random();
            Bitmap bmp = pics[ generator.Next(pics.Count) ] as Bitmap;
            if(!(null==bmp))
            {
                pBox.Image = bmp;
            }
            bmp = null;
            generator = null;
        }

        private void Form1_Load(object sender, System.EventArgs e)
        {            
            Stream imgStream = null;
            Bitmap bmp = null;            

            // get a reference to the current assembly
            Assembly a = Assembly.GetExecutingAssembly();
        
            // get a list of resource names from the manifest
            string [] resNames = a.GetManifestResourceNames();

            // populate the textbox with information about our resources
            // also look for images and put them in our arraylist
            txtInfo.Clear();
            
            txtInfo.Text += String.Format("Found {0} resources\r\n", resNames.Length);
            txtInfo.Text += "----------\r\n";
            foreach(string s in resNames)
            {
                txtInfo.Text += s + "\r\n";
                if(s.EndsWith(".bmp"))
                {
                    // attach to stream to the resource in the manifest
                    imgStream = a.GetManifestResourceStream(s);
                    if( !(null==imgStream) )
                    {                    
                        // create a new bitmap from this stream and 
                        // add it to the arraylist
                        bmp = Bitmap.FromStream( imgStream ) as Bitmap;
                        if( !(null==bmp) )
                        {
                            pics.Add( bmp );
                        }
                        bmp = null;
                        imgStream.Close();
                        imgStream = null;
                    }
                }
            }            
            txtInfo.Text += "----------\r\n";
            txtInfo.Text += String.Format("Found {0} Bitmaps\r\n",
                pics.Count);                        
        }
    }
}

Return to Browsing Tutorials

Email this Tutorial to a Friend

Rate this Content:  
low quality  1 2 3 4 5  high quality

Reader's Comments Post a Comment
 
good reading material
-- Vijay Venkatachalam, December 11, 2001
 
Whoa! You put a lot of work into this, nice!
-- Jun Nozaki, January 30, 2002
 
Great tutorial.
-- Brian Simoneau, February 26, 2002
 
Wow.. that was an awesome tutorial. I'm going to go mess with embedding resources in my C# application now =)

Do you know what C# can handle? Like Jpgs and Gifs?
-- Victor Vuong, March 01, 2002
 
Very nice!
-- Kuniaki Tran, March 03, 2002
 
I would imagine you can embed any types of files as resources, and use them as you see fit. It also seems reasonable to assume that C# can also handle jpegs/gif's. I'll definatly be playing around with the info i've learned here, great job.
-- Lee B, April 07, 2002
 
Is there a way to do this without using Visual Studio?
-- Lee B, April 08, 2002
 
In case anyone is still curious, C# certainly has support for all sorts of graphics formats, including PNG, JPEG, GIF, etc... All of them can be used via the "Image" class!
-- John Gallardo, April 30, 2002
 
Thanks a lot! This tutorial was exactly what I needed today. what a life saver :-).
-- Aaron Brethorst, November 23, 2002
 
good presentation... but what i need is to access imbedded dll file instead of bitmaps or icons... is it possible? thanks a lot!
-- gani torres, February 14, 2003
 
Great work. I will send you the extra advil that I had set aside for solving this problem.
-- Robert Zhu, June 03, 2003
 
Great tutorial, helped me embed icons for my Notepad replacement program that I'm building. Now if only I could figure out a good undo function. Maybe something with timers....
-- Bojan Rajkovic, April 29, 2004
 
Great tutorial! But I had problems if I closed the stream after the bitmap was loaded from it. Anyone else run into this?
-- Mark M, May 05, 2004
 
Indeed, if the stream is closed, you can't use the image any more. We'll just have to see what we can do about that.
-- David Johnson, August 20, 2004
 
So. Since Bitmap.FromStream requires that you leave the stream open for the duration of the image's usage, one way out of this is to NOT close the stream, but rather just "forget about it". That seems a little wierd but a call like this would hide behaviour in a more reasonable way (it may just do the same thing anyway)

bmp = new Bitmap(_assembly.GetManifestResourceStream(name));

// The snippet would look like this:
bmp = new Bitmap(a.GetManifestResourceStream(s));
if( !(null==bmp) )
{
pics.Add( bmp );
}
bmp = null;

// and probably some exception handling for missing resources.
-- David Johnson, August 20, 2004
 
I used some of your code here to store and stream DirectX .X mesh files in my resources for a game I'm working on. I can load them all into an array before the game starts (along with their material and texture data that can also be stored/streamed in the same manner) and save processing time for files while the game is being played.

I did not run into any issues with using streamed meshes once the stream was closed (perhaps I misunderstood what was meant in the comments above?).

Incase anyone is interested in this:

string file = "Spaceship.x";
Stream meshStream = null;
Mesh tempMesh = null;
Assembly a = Assembly.GetExecutingAssembly();
string [] resNames = a.GetManifestResourceNames();
foreach(string s in resNames)
{
if(s.EndsWith( file ) )
{
meshStream = a.GetManifestResourceStream(s);
if( meshStream != null )
{
tempMesh = Mesh.FromStream( meshStream, MeshFlags.Managed, device, out mtrl ) as Mesh;
//--^tempMesh is now your mesh file from resources.
//--^You may place it in a Mesh array along with its materials
//--^which you would retrieve in this if statement
}
meshStream.Close();
meshStream = null;
}
}
-- Cyric -, August 31, 2004
 
yeah, any C# guru here can teach me how to embed icon files?
Thanks for your great tutorials for bitmap files.
-- Brian Su, September 09, 2004
 
Did I miss something?

// get a reference to the current assembly
Assembly a = Assembly.GetExecutingAssembly();

That won't get a reference to the current assembly, that'll get a reference to a nonstatic assembly.

The compiler will throw on that I think.
-- Dan Astair, April 06, 2005
 
Nope, it works as stated in VS 2003...
I used this tutorial to imbed XML files into my NUnit test DLL, and it works perfectly.

-- d b, October 06, 2005
 
Copyright © 2001 DevHood® All Rights Reserved