Resources in .resx File Format

The .resx resource file format consists of XML entries, which specify objects and strings inside XML tags. One advantage of a .resx file is that when you open the file with a text editor (such as Notepad or Microsoft Word), you can write to it, parse it, and manipulate it. When viewing a .resx file, you can actually see the binary form of an embedded object (for example, a picture) when this binary information is a part of the resource manifest. Apart from this binary information, a .resx file is completely readable and maintainable.

Note

Do not use resource files to store passwords, security-sensitive information, or private data.

A .resx file contains a standard set of header information, which describes the format of the resource entries and specifies the versioning information for the XML used to parse the data. The following example shows what a typical set of header statements in a .resx file might look like.

<?xml version="1.0" encoding="utf-8"?>
<root>
  <xsd:schema id="root"  xmlns:xsd="https://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
  <xsd:element name="data">
    <xsd:complexType>
      <xsd:sequence>
        <xsd:element name="value" type="xsd:string" minOccurs="0"                     msdata:Ordinal="2" />
      </xsd:sequence>
      <xsd:attribute name="name" type="xsd:string" />
      <xsd:attribute name="type" type="xsd:string" />
      <xsd:attribute name="mimetype" type="xsd:string" />
    </xsd:complexType>
  </xsd:element>

Following the header information, each entry is described as a name/value pair, very similar to the way in which strings are specified in a .txt file. A name/value pair in the .resx format is wrapped in XML code, which describes string or object values. When a string is added to a .resx file, the name of the string is embedded in a <data> tag, and the value is enclosed in a <value> tag, as in the following example.

    <data name="string1">
      <value>hello</value>
    </data>

When an object is inserted into a .resx file, the same <data> and <value> tags are used to describe the entry, but the <data> tag includes either a type or MIME type specifier. The type specifier holds the data type of the object being saved. The MIME type specifier holds the base type (Base64) of the binary information stored, if the object consists of binary data.

Note

All .resx files use a binary serialization formatter to generate and parse the binary data for a specified type. As a result, a .resx file can become invalid if the binary serialization format for an object changes in an incompatible way.

The following example shows an Int32 object saved in a .resx file, and the beginning of a bitmap object, which holds the binary information from an actual .gif file.

    <data name="i1" type="System.Int32, mscorlib">
      <value>20</value>
    </data>

    <data name="flag" type="System.Drawing.Bitmap, System.Drawing,   
    Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" 
    mimetype="application/x-microsoft.net.object.bytearray.base64">
      <value>
        AAEAAAD/////AQAAAAAAAAAMAgAAADtTeX…
      </value>
    </data>

Creating a .resx File

You can use the System.Resources.ResXResourceWriter class to create a .resx file directly from code. The following example illustrates how to create a .resx file that stores an icon and a string as resources inside the file. Create a ResXResourceWriter with a unique file name. Call the ResXResourceWriter.AddResource method for each resource to add to the file. Finally, call the ResXResourceWriter.Close method, or create a ResXResourceWriter within a using statement, to write the resource information to the resource file.

Public Shared Function MakeResXFile() As String
    Dim resxName As String = "MyResX.resx"
    Using resxWriter As New ResXResourceWriter(resxName)
        resxWriter.AddResource("MyFormTitle", "My Resource List Form")
        resxWriter.AddResource("MyFormIcon", SystemIcons.Warning)
    End Using

    Return resxName
End Function
public static string MakeResXFile()
{
    string resxName = "MyResX.resx";
    using (ResXResourceWriter resxWriter = new ResXResourceWriter(resxName))
    {
        resxWriter.AddResource("MyFormTitle", "My Resource List Form");
        resxWriter.AddResource("MyFormIcon", SystemIcons.Warning);
    }

    return resxName;
}
static String^ MakeResXFile()
{
    String^ resxName = "MyResX.resx";
    ResXResourceWriter^ resxWriter = gcnew ResXResourceWriter(resxName);
    resxWriter->AddResource("MyFormTitle", "My Resource List Form");
    resxWriter->AddResource("MyFormIcon", SystemIcons::Warning);
    resxWriter->Close();

    return resxName;
}

You can also manipulate a .resx file directly. However, to avoid corrupting the file, be careful not to modify any binary information that is stored in the file.

You cannot embed a .resx file in a runtime executable or compile it into a satellite assembly. You must convert your .resx file into a .resources file by using Resgen.exe (Resource File Generator). For more information, see Resources in .Resources File Format.

Enumerating Resources

If you want to retrieve the names and values of the resources in a .resx file, use the System.Resources.ResXResourceReader class. This class provides an enumerator for all the resources in the .resx file. The following example demonstrates how to create a ResXResourceReader for a specified file, iterate through the file, and add the names and values of resources to a list in a form.

Using resxReader As New ResXResourceReader(resxFile)
    Dim resItem As ListViewItem
    For Each entry As DictionaryEntry In resxReader
        resItem = new ListViewItem(CType(entry.Key, String))
        resItem.SubItems.Add(entry.Value.GetType().FullName)
        resList.Items.Add(resItem)
    Next entry
End Using
using (ResXResourceReader resxReader = new ResXResourceReader(resxFile))
{
    ListViewItem resItem;
    foreach (DictionaryEntry entry in resxReader)
    {
        resItem = new ListViewItem((string)entry.Key);
        resItem.SubItems.Add(entry.Value.GetType().FullName);
        resList.Items.Add(resItem);
    }
}
ResXResourceReader^ resxReader = gcnew ResXResourceReader(resxFile);
ListViewItem^ resItem;
for each (DictionaryEntry entry in resxReader)
{
    resItem = gcnew ListViewItem((String^)entry.Key);
    resItem->SubItems->Add(entry.Value->GetType()->FullName);
    resList->Items->Add(resItem);
}
resxReader->Close();

Selecting a Resource

To retrieve a resource explicitly by name, use the System.Resources.ResXResourceSet class. The GetObject and GetString methods are used to get the value of a named resource. The following example retrieves both a form title string and a form icon by their resource names.

Using resxSet As New ResXResourceSet(resxFile)
    MyClass.Text = resxSet.GetString("MyFormTitle")
    MyClass.Icon = CType(resxSet.GetObject("MyFormIcon"), Icon)
End Using
using (ResXResourceSet resxSet = new ResXResourceSet(resxFile))
{
    this.Text = resxSet.GetString("MyFormTitle");
    this.Icon = (Icon)resxSet.GetObject("MyFormIcon");
}
ResXResourceSet^ resxSet = gcnew ResXResourceSet(resxFile);
this->Text = resxSet->GetString("MyFormTitle");
this->Icon = (::Icon^)resxSet->GetObject("MyFormIcon");
resxSet->Close();

Loading Resources from a .resx File

The following example illustrates the use of all the .resx manipulation classes mentioned in the previous sections. Before constructing and displaying the form, a .resx file is created with two resource items: a form title string and an icon to set as the form icon. In the constructor, the title string and icon are retrieved by using the ResXResourceSet class. Finally, the resources in the .resx file are enumerated and added to a list shown in the form's body. The text of the .resx file that was created is viewed by pressing the Show ResX button in the form.

Imports System
Imports System.Resources
Imports System.Collections
Imports System.Diagnostics
Imports System.Drawing
Imports System.Windows.Forms

Public Class ResXViewForm
    Inherits Form

    Private resxFile As String

    Public Shared Function MakeResXFile() As String
        Dim resxName As String = "MyResX.resx"
        Using resxWriter As New ResXResourceWriter(resxName)
            resxWriter.AddResource("MyFormTitle", "My Resource List Form")
            resxWriter.AddResource("MyFormIcon", SystemIcons.Warning)
        End Using

        Return resxName
    End Function

    Public Sub New(resxFile As String)
        MyClass.resxFile = resxFile

        Using resxSet As New ResXResourceSet(resxFile)
            MyClass.Text = resxSet.GetString("MyFormTitle")
            MyClass.Icon = CType(resxSet.GetObject("MyFormIcon"), Icon)
        End Using

        Dim margin As Integer = 10
        Dim resList As New ListView()
        resList.Bounds = New Rectangle(New Point(margin, margin), New Size(300, 60))
        resList.View = View.Details
        resList.GridLines = True
        resList.Columns.Add("Resource Name", resList.ClientSize.Width \ 2)
        resList.Columns.Add("Type", resList.ClientSize.Width \ 2)
        Using resxReader As New ResXResourceReader(resxFile)
            Dim resItem As ListViewItem
            For Each entry As DictionaryEntry In resxReader
                resItem = new ListViewItem(CType(entry.Key, String))
                resItem.SubItems.Add(entry.Value.GetType().FullName)
                resList.Items.Add(resItem)
            Next entry
        End Using

        Dim resxButton As New Button()
        resxButton.Text = "Show ResX"
        AddHandler resxButton.Click, AddressOf resxButton_Click
        resxButton.Location = New Point(resList.Bounds.Left,
            resList.Bounds.Bottom + margin)

        Dim okButton As New Button()
        okButton.Text = "OK"
        AddHandler okButton.Click, AddressOf okButton_Click
        okButton.Location = new Point(resList.Bounds.Right - okButton.Width,
            resList.Bounds.Bottom + margin)

        MyClass.ClientSize = New Size(resList.Width + margin * 2,
            okButton.Top + okButton.Height + margin)

        MyClass.FormBorderStyle = FormBorderStyle.FixedDialog
        MyClass.MaximizeBox = False
        MyClass.MinimizeBox = False
        MyClass.StartPosition = FormStartPosition.CenterScreen
        MyClass.Controls.Add(resList)
        MyClass.Controls.Add(resxButton)
        MyClass.Controls.Add(okButton)
    End Sub

    Private Sub resxButton_Click(sender As Object, e As EventArgs)
        Process.Start("Notepad.exe", MyClass.resxFile)
    End Sub

    Private Sub okButton_Click(sender As Object, e As EventArgs)
        Application.Exit()
    End Sub

    Public Shared Sub Main()
        Dim resxFile As String = MakeResXFile()

        Application.Run(New ResXViewForm(resxFile))
    End Sub
End Class
using System;
using System.Resources;
using System.Collections;
using System.Diagnostics;
using System.Drawing;
using System.Windows.Forms;

public class ResXViewForm : Form
{
    private string resxFile;

    public static string MakeResXFile()
    {
        string resxName = "MyResX.resx";
        using (ResXResourceWriter resxWriter = new ResXResourceWriter(resxName))
        {
            resxWriter.AddResource("MyFormTitle", "My Resource List Form");
            resxWriter.AddResource("MyFormIcon", SystemIcons.Warning);
        }

        return resxName;
    }

    public ResXViewForm(string resxFile)
    {
        this.resxFile = resxFile;

        using (ResXResourceSet resxSet = new ResXResourceSet(resxFile))
        {
            this.Text = resxSet.GetString("MyFormTitle");
            this.Icon = (Icon)resxSet.GetObject("MyFormIcon");
        }

        int margin = 10;
        ListView resList = new ListView();
        resList.Bounds = new Rectangle(new Point(margin, margin), new Size(300, 60));
        resList.View = View.Details;
        resList.GridLines = true;
        resList.Columns.Add("Resource Name", resList.ClientSize.Width / 2);
        resList.Columns.Add("Type", resList.ClientSize.Width / 2);
        using (ResXResourceReader resxReader = new ResXResourceReader(resxFile))
        {
            ListViewItem resItem;
            foreach (DictionaryEntry entry in resxReader)
            {
                resItem = new ListViewItem((string)entry.Key);
                resItem.SubItems.Add(entry.Value.GetType().FullName);
                resList.Items.Add(resItem);
            }
        }

        Button resxButton = new Button();
        resxButton.Text = "Show ResX";
        resxButton.Click += new EventHandler(resxButton_Click);
        resxButton.Location = new Point(resList.Bounds.Left,
            resList.Bounds.Bottom + margin);

        Button okButton = new Button();
        okButton.Text = "OK";
        okButton.Click += new EventHandler(okButton_Click);
        okButton.Location = new Point(resList.Bounds.Right - okButton.Width,
            resList.Bounds.Bottom + margin);

        this.ClientSize = new Size(resList.Width + margin * 2,
            okButton.Top + okButton.Height + margin);

        this.FormBorderStyle = FormBorderStyle.FixedDialog;
        this.MaximizeBox = false;
        this.MinimizeBox = false;
        this.StartPosition = FormStartPosition.CenterScreen;
        this.Controls.Add(resList);
        this.Controls.Add(resxButton);
        this.Controls.Add(okButton);
    }

    private void resxButton_Click(object sender, EventArgs e)
    {
        Process.Start("Notepad.exe", this.resxFile);
    }

    private void okButton_Click(object sender, EventArgs e)
    {
        Application.Exit();
    }

    public static void Main()
    {
        string resxFile = MakeResXFile();

        Application.Run(new ResXViewForm(resxFile));
    }
}
#using <System.dll>
#using <System.Drawing.dll>
#using <System.Windows.Forms.dll>

using namespace System;
using namespace System::Resources;
using namespace System::Collections;
using namespace System::Diagnostics;
using namespace System::Drawing;
using namespace System::Windows::Forms;

public ref class ResXViewForm : public Form
{
private:
    String^ resxFile;

public:
    static String^ MakeResXFile()
    {
        String^ resxName = "MyResX.resx";
        ResXResourceWriter^ resxWriter = gcnew ResXResourceWriter(resxName);
        resxWriter->AddResource("MyFormTitle", "My Resource List Form");
        resxWriter->AddResource("MyFormIcon", SystemIcons::Warning);
        resxWriter->Close();

        return resxName;
    }

    ResXViewForm(String^ resxFile)
    {
        this->resxFile = resxFile;

        ResXResourceSet^ resxSet = gcnew ResXResourceSet(resxFile);
        this->Text = resxSet->GetString("MyFormTitle");
        this->Icon = (::Icon^)resxSet->GetObject("MyFormIcon");
        resxSet->Close();

        int margin = 10;
        ListView^ resList = gcnew ListView();
        resList->Bounds = Rectangle(margin, margin, 300, 60);
        resList->View = View::Details;
        resList->GridLines = true;
        resList->Columns->Add("Resource Name", resList->ClientSize.Width / 2);
        resList->Columns->Add("Type", resList->ClientSize.Width / 2);
        ResXResourceReader^ resxReader = gcnew ResXResourceReader(resxFile);
        ListViewItem^ resItem;
        for each (DictionaryEntry entry in resxReader)
        {
            resItem = gcnew ListViewItem((String^)entry.Key);
            resItem->SubItems->Add(entry.Value->GetType()->FullName);
            resList->Items->Add(resItem);
        }
        resxReader->Close();

        Button^ resxButton = gcnew Button();
        resxButton->Text = "Show ResX";
        resxButton->Click += gcnew EventHandler(this, &ResXViewForm::resxButton_Click);
        resxButton->Location = Point(resList->Bounds.Left,
            resList->Bounds.Bottom + margin);

        Button^ okButton = gcnew Button();
        okButton->Text = "OK";
        okButton->Click += gcnew EventHandler(this, &ResXViewForm::okButton_Click);
        okButton->Location = Point(resList->Bounds.Right - okButton->Width,
            resList->Bounds.Bottom + margin);

        this->ClientSize = ::Size(resList->Width + margin * 2,
            okButton->Top + okButton->Height + margin);

        this->FormBorderStyle = ::FormBorderStyle::FixedDialog;
        this->MaximizeBox = false;
        this->MinimizeBox = false;
        this->StartPosition = FormStartPosition::CenterScreen;
        this->Controls->Add(resList);
        this->Controls->Add(resxButton);
        this->Controls->Add(okButton);
    }

private:
    void resxButton_Click(Object^ sender, EventArgs^ e)
    {
        Process::Start("Notepad.exe", this->resxFile);
    }

    void okButton_Click(Object^ sender, EventArgs^ e)
    {
        Application::Exit();
    }

public:
    static void Main()
    {
        String^ resxFile = MakeResXFile();

        Application::Run(gcnew ResXViewForm(resxFile));
    }
};

int main()
{
    ResXViewForm::Main();
}

See Also

Reference

Resgen.exe (Resource File Generator)

Concepts

Creating Resource Files

Resources in .Resources File Format