Microsoft KB Archive/816181

From BetaArchive Wiki

Article ID: 816181

Article Last Modified on 5/16/2007



APPLIES TO

  • Microsoft Visual C++ .NET 2003 Standard Edition
  • Microsoft .NET Framework 1.1
  • Microsoft Visual C++ 2005 Express Edition



For a Microsoft Visual Basic .NET version of this article, see 319291.

For a Microsoft Visual C# .NET version of this article, see 319292 .



This article refers to the following Microsoft .NET Framework Class Library namespace:

  • System::IO
  • System::Reflection
  • System::ComponentModel
  • System::Collections
  • System::Windows::Forms
  • System::Data
  • System::Drawing

IN THIS TASK

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 top

Overview

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 top

Embed 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 top

Add embedded resources

To add a text file and an image file to your project as embedded resources, follow these steps:

  1. Start Microsoft Visual Studio .NET 2003 or Microsoft Visual Studio 2005.
  2. On the File menu, point to New, and then click Project.
  3. 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.

  1. In the Name box, type MyApplication, and then click OK.
  2. In Solution Explorer, right-click MyApplication, point to Add, and then click Add New Item.
  3. In the Add New Item dialog box, under Templates, click Text File (.txt).
  4. Name the file as MyTextFile.txt, and then click Open.


Note In Visual Studio 2005, click Add.

  1. When the file opens in the editor, add some text to the text file.
  2. Save, and then close the file.
  3. 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.
  4. When the new image is opened in the editor, draw something on the image.
  5. Save, and then close the file.
  6. In Solution Explorer, right-click MyApplication, and then click Properties.
  7. In the MyApplication Property Pages dialog box, expand Linker, and then click Input.
  8. 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.

  1. 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 top

Access the resources

To access the resources that you have embedded in the Manifest of your assembly, follow these steps:

  1. 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.

  2. Declare the following member variables in the Form1 class:

    private: Assembly *_assembly;
    private: Stream *_imageStream;
    private: StreamReader *_textStreamReader;
  3. To access the Load event for the form in the Code Editor, double-click the form in Design mode.
  4. 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();
  5. 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"));
  6. 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 top

Display 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:

  1. Add a PictureBox control to the form.
  2. Add a Button control to the form, and then change its Text property to Show Image.
  3. 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.

  4. Switch to Design mode, and then add a TextBox control to the form.
  5. Add another Button control to the form, and then change its Text property to Get Text.
  6. 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); 
    }
  7. Press CTRL+B to build the solution.
  8. Press CTRL+F5 to run the program.

back to the top

Full 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:

  1. Click Project, and then click <ProjectName> Properties.


Note<ProjectName> is a placeholder for the name of the project.

  1. Expand Configuration Properties, and then click General.
  2. 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:

/clr (Common Language Runtime Compilation)
http://msdn2.microsoft.com/en-us/library/k8d11d4s.aspx


back to the top

Troubleshooting

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


Keywords: kbbitmap kbwindowsforms kbresource kbhowtomaster KB816181