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)