Embedding and Using Resources in C#

John Gallardo ([email protected])

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 description for Form1.
    /// 
    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;
        /// 
        /// Required designer variable.
        /// 
        private System.ComponentModel.Container components = null;

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

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

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

        #region Windows Form Designer generated code
        /// 
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// 
        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

        /// 
        /// The main entry point for the application.
        /// 
        [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);                        
        }
    }
}

你可能感兴趣的:(VSTO)