SUMMARY
This step-by-step article describes how to use Microsoft
Visual C++ .NET or Microsoft Visual C++ 2005 to embed resources as part of the assembly and then how to
access these resources at run time.
back to the topOverview
The .NET Framework can encapsulate files as part of a compiled
assembly. These files are known as embedded resources. These resources are
completely separate from the .rc files and the .resx files that are associated
with the assembly. You can access these resources at run time through the
Assembly class of the
System.Reflection namespace.
A major advantage of embedding resources to
the Manifest is that because the files are part of your compiled assembly, the
user cannot accidentally delete or misplace files that are critical to your
program and that sometimes may prevent the execution of your program. One
limitation of this approach is that you cannot save any changes to this file to
the assembly without recompiling the program. Because of this limitation,
include only those files that will not change during the lifetime of your
program as an embedded resource.
back
to the topEmbed and then access resources
To add embedded resources to your project, you must first add the
files as part of your project. After you have added the files to your project,
you can access and display the resources through the
System.Reflection namespace.
back to the
topAdd embedded resources
To add a text file and an image file to your project as embedded
resources, follow these steps:
- Start Microsoft Visual Studio .NET 2003 or Microsoft Visual Studio 2005.
- On the File menu, point to
New, and then click Project.
- Click Visual C++ Projects under
Project Types, and then click Windows Forms
Application (.NET) under Templates.
Note In Visual Studio 2005, click Visual C++ under
Project Types, and then click Windows Forms
Application under Templates. - In the Name box, type
MyApplication, and then click
OK.
- In Solution Explorer, right-click
MyApplication, point to Add, and then click
Add New Item.
- In the Add New Item dialog box, under
Templates, click Text File (.txt).
- Name the file as MyTextFile.txt, and then click
Open.
Note In Visual Studio 2005, click Add. - When the file opens in the editor, add some text to the
text file.
- Save, and then close the file.
- Repeat steps 5 and 6 to add a bitmap image to your project,
but instead of clicking Text File (.txt), click Bitmap
File (.bmp), and then change the file name to MyImage.bmp.
- When the new image is opened in the editor, draw something
on the image.
- Save, and then close the file.
- In Solution Explorer, right-click
MyApplication, and then click
Properties.
- In the MyApplication Property Pages dialog
box, expand Linker, and then click
Input.
- In the Embed Managed Resource File field,
type the file names that you recently added to the project. For example, you
can type MyTextFile.txt; MyImage.bmp.
The next
time that you build the project, the compiler adds these files to your
assembly. - Click OK.
Note The resource file names are case-sensitive. When you access the
resources, you must use the exact spelling and case of the file name. If you do
not use the exact spelling and case of the file name, the method call to access
the
ManifestResourceStream stream returns
NULL, and the system does not raise an exception.
If you
want to verify the resource names, you can use the Microsoft intermediate
language (MSIL) Disassembler (Ildasm.exe) to view the Manifest data. The
Manifest data lists the included resources.
back to the topAccess the resources
To access the resources that you have embedded in the Manifest of
your assembly, follow these steps:
- Import the System::IO and the System::Reflection namespaces. To do this, add the following code in the Code Editor
after the other using directives:
using namespace System::IO;
using namespace System::Reflection;
The System::IO namespace provides the definition of a stream and the System::Reflection namespace defines the Assembly class that provides methods to access the resources that are
embedded in your assembly. - Declare the following member variables in the Form1 class:
private: Assembly *_assembly;
private: Stream *_imageStream;
private: StreamReader *_textStreamReader;
- To access the Load event for the form in the Code Editor, double-click the form in
Design mode.
- To read the resource from the assembly that is executing
the current code, you must obtain an instance of that assembly. To do this, use
the GetExecutingAssembly method of the assembly in the Form1_Load event handler, as follows:
_assembly = Assembly::GetExecutingAssembly();
- Reading the information from the resource to a stream is
performed with a method call to the GetManifestResourceStream method. The parameter that is passed to this method is the name
of the resource that is to be accessed. The two resources are then read to
their corresponding streams as the Load event of the form is executed. To do this, add the following code
to Form1_Load event handler:
_imageStream = _assembly->GetManifestResourceStream(S"MyImage.bmp");
_textStreamReader = new StreamReader(_assembly->GetManifestResourceStream(S"MyTextFile.txt"));
- Set up an exception-handling mechanism for the code in the Form1_Load event handler by using the try and catch blocks as follows:
try
{
_assembly = Assembly::GetExecutingAssembly();
_imageStream = _assembly->GetManifestResourceStream(S"MyImage.bmp");
_textStreamReader = new StreamReader(_assembly->GetManifestResourceStream(S"MyTextFile.txt"));
}
catch(Exception *ex)
{
MessageBox::Show("Error accessing resources!",ex->Message);
}
The try-catch block, known as structured error handling in Visual C++ .NET, is
used to catch any errors that may have occurred while the instance of the Assembly class accesses the resources.
back to the topDisplay the resources
This example uses two
Button controls to display the embedded resources. When you click the
first button, a bitmap image that is based on the resource that is read from
the assembly is created and displays in the
PictureBox control of the form. When you click the second button, text is
read from a text resource and the text displays in a text box.
To
display the embedded resources, follow these steps:
- Add a PictureBox control to the form.
- Add a Button control to the form, and then
change its Text property to Show
Image.
- Double-click Show Image to open its Click event in the code viewer, and then paste the following code in
the event handler:
try
{
pictureBox1->Image = new Bitmap(_imageStream);
}
catch(Exception *ex)
{
MessageBox::Show("Error creating image!",ex->Message);
}
This code generates a new instance of a bitmap that is based on the
resource stream that was read in the Load event of the form. - Switch to Design mode, and then add a
TextBox control to the form.
- Add another Button control to the form,
and then change its Text property to Get
Text.
- Double-click Get Text to open the Click event for the button, and then paste the following code in the
event handler:
try
{
if(_textStreamReader->Peek() != 1)
{
textBox1->Text = _textStreamReader->ReadLine();
}
}
catch(Exception *ex)
{
MessageBox::Show("Error writing text!",ex->Message);
}
- Press CTRL+B to build the
solution.
- Press CTRL+F5 to run the
program.
back to the topFull code
#pragma once
namespace MyApplication
{
using namespace System;
using namespace System::ComponentModel;
using namespace System::Collections;
using namespace System::Windows::Forms;
using namespace System::Data;
using namespace System::Drawing;
using namespace System::IO;
using namespace System::Reflection;
/// <summary>
/// Summary for Form1
///
/// WARNING: If you change the name of this class, you will need to change the
/// 'Resource File Name' property for the managed resource compiler tool
/// associated with all .resx files this class depends on. Otherwise,
/// the designers will not be able to interact properly with localized
/// resources associated with this form.
/// </summary>
public __gc class Form1 : public System::Windows::Forms::Form
{
private: Assembly *_assembly;
private: Stream *_imageStream;
private: StreamReader *_textStreamReader;
private: System::Windows::Forms::PictureBox * pictureBox1;
private: System::Windows::Forms::Button* button1;
private: System::Windows::Forms::TextBox* textBox1;
private: System::Windows::Forms::Button* button2;
public:
Form1(void)
{
InitializeComponent();
}
protected:
void Dispose(Boolean disposing)
{
if (disposing && components)
{
components->Dispose();
}
__super::Dispose(disposing);
}
private:
/// <summary>
/// Required designer variable.
/// </summary>
System::ComponentModel::Container * components;
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
void InitializeComponent(void)
{
this->pictureBox1 = new System::Windows::Forms::PictureBox();
this->button1 = new System::Windows::Forms::Button();
this->textBox1 = new System::Windows::Forms::TextBox();
this->button2 = new System::Windows::Forms::Button();
this->SuspendLayout();
//
// pictureBox1
//
this->pictureBox1->Location = System::Drawing::Point(8, 8);
this->pictureBox1->Name = S"pictureBox1";
this->pictureBox1->Size = System::Drawing::Size(280, 152);
this->pictureBox1->TabIndex = 0;
this->pictureBox1->TabStop = false;
//
// button1
//
this->button1->Location = System::Drawing::Point(8, 184);
this->button1->Name = S"button1";
this->button1->TabIndex = 1;
this->button1->Text = S"Show Image";
this->button1->Click += new System::EventHandler(this, button1_Click);
//
// textBox1
//
this->textBox1->Location = System::Drawing::Point(96, 224);
this->textBox1->Name = S"textBox1";
this->textBox1->Size = System::Drawing::Size(184, 20);
this->textBox1->TabIndex = 2;
this->textBox1->Text = S"textBox1";
//
// button2
//
this->button2->Location = System::Drawing::Point(8, 224);
this->button2->Name = S"button2";
this->button2->TabIndex = 3;
this->button2->Text = S"Get Text";
this->button2->Click += new System::EventHandler(this, button2_Click);
//
// Form1
//
this->AutoScaleBaseSize = System::Drawing::Size(5, 13);
this->ClientSize = System::Drawing::Size(292, 266);
this->Controls->Add(this->button2);
this->Controls->Add(this->textBox1);
this->Controls->Add(this->button1);
this->Controls->Add(this->pictureBox1);
this->Name = S"Form1";
this->Text = S"Form1";
this->Load += new System::EventHandler(this, Form1_Load);
this->ResumeLayout(false);
}
private: System::Void Form1_Load(System::Object * sender, System::EventArgs * e)
{
try
{
_assembly = Assembly::GetExecutingAssembly();
_imageStream = _assembly->GetManifestResourceStream(S"MyImage.bmp");
_textStreamReader = new StreamReader(_assembly->GetManifestResourceStream(S"MyTextFile.txt"));
}
catch(Exception *ex)
{
MessageBox::Show("Error accessing resources!",ex->Message);
}
}
private: System::Void button1_Click(System::Object * sender, System::EventArgs * e)
{
try
{
pictureBox1->Image = new Bitmap(_imageStream);
}
catch(Exception *ex)
{
MessageBox::Show("Error creating image!",ex->Message);
}
}
private: System::Void button2_Click(System::Object * sender, System::EventArgs * e)
{
try
{
if(_textStreamReader->Peek() != 1)
{
textBox1->Text = _textStreamReader->ReadLine();
}
}
catch(Exception *ex)
{
MessageBox::Show("Error writing text!",ex->Message);
}
}
};
}
Note You must add the common language runtime support compiler option (/clr:oldSyntax) in Visual C++ 2005 to successfully compile the previous code sample.
To add the common language runtime support compiler option in Visual C++ 2005, follow these steps:
- Click Project, and then click <ProjectName> Properties.
Note<ProjectName> is a placeholder for the name of the project. - Expand Configuration Properties, and then click General.
- Click to select Common Language Runtime Support, Old Syntax (/clr:oldSyntax) in the Common Language Runtime support project setting on the right pane, click Apply, and then click OK.
For more information about the common language runtime support compiler options, visit the following Microsoft
Developer Network (MSDN) Web site:
back to the topTroubleshooting
Because resource names are case-sensitive, verify that you are
using the correct spelling and case of the resources that are accessed. To
verify the exact spelling of the resources, use the Ildasm.exe tool to read the
Manifest data.
back to the
top