String Resources

To create string resources, simply perform the following three steps:

  1. Create a text file that contains a name-value entry for each string.

  2. Convert the text file into a .resources file using Resgen.exe.

  3. Create a DLL, and embed the .resources file using the Assembly Generation Tool (AL) or one of the language compilers that ships with the .NET Framework SDK.

    NoteFor more information on AL, see Appendix B: Resource Tools.

If the strings are localized into nondefault cultures, you must perform the preceding three steps for each of the cultures as well as for a default, language-neutral culture. You must also specify the culture when using AL.

Listing 1. Sample Strings Text File (MyStrings.txt)

; Sample strings for the calculator – Default locale
;
Math_Greeting = Welcome – Integer Calculator
Math_Formula_Label = Formula and Results:
Math_Clear_Button = Clear
Math_Calc_Button = Calculate
Math_Calc_Error = Invalid Formula. Please try again.

Resgen.exe converts among the three resource-file formats: strings (.txt file), XML resources (.resx file), and compiled (.resources file). To compile the MyStrings.txt resource file, use the following command line to generate an intermediate, compiled file that contains multiple resources:

resgen MyStrings.txt MyStrings.resources

At this point, you have three packaging options: embedding the resources into your executable assembly, creating satellite assemblies that just hold resources, or leaving the resources in the .resources file and accessing them directly. The last option is useful mostly for tools; true applications should use assemblies to gain the benefits of signature and version checking.

For many applications — particularly those that are not localized — it is sufficient to embed the resources into the executable assembly. This is done at compile time using the /res switch and the following syntax:

(csc|vbc) ... /out:WorldCalc.exe /res:MyStrings.resources WorldCalc.cs

NoteFor clarity, the /target, /addmodule, /a, and /r parameters were omitted from the previous line.

The previous command line compiles WorldCalc.cs into WorldCalc.exe, and embeds the resources from the MyStrings.resources file. If you wanted to put the resources into a separate DLL, you could use a command line like the following:

al /out:WorldCalc.Resources.DLL /embed:MyStrings.resources,MyStrings.resources,Private

The /embed parameter uses the following syntax:

/embed:<filename>[,<name>[,Private]

The parameters are described in the following table.

  • <filename> — The name of the .resources file.

  • <name> — The internal name for the resources. Typically used when constructing a ResourceManager. Commonly includes a namespace.

  • Private — Whether the resources are visible to other assemblies. (The default is no.)

    NoteYou can use the /link parameter rather than /embed. This builds the resources assembly DLL (which contains the manifest), but it includes a link to the .resources file rather than embedding the resources themselves.

Creating Resources Using Code

You can use code to directly create .resource files. This technique is useful when automating the generation of appropriately formatted resources — specifically, when the resources are stored in a database or have migrated from a different system, such as one that uses earlier Win32 string resource tables. To create a .resources file, create a ResourceWriter with a unique file name, call AddResource at least once, and call Close (which implicitly calls Generate) to close the file. The following small program illustrates using a ResourceWriter to create a .resources file with five entries.

Listing 2a. Creating and Reading .resource Files (ResWrite.cs)

using System;
using System.Collections;
using System.Resources;

class MainApp {
   public static void Main() {
      // First create the resource file and add strings.
      IResourceWriter rw = new ResourceWriter("sample.resources");
      rw.AddResource("test1", "one");
      rw.AddResource("test2", "two");
      rw.AddResource("test3", "three");
      rw.AddResource("test4", "four");
      rw.AddResource("test5", 512341234);
      rw.Close();
      ...
   }
}

Listing 2b. Creating and Reading .resource Files (ResWrite.vb)

Imports System
Imports System.Collections
Imports System.Resources

Class MainApp
    
   Public Shared Sub Main()
      ' First create the resource file and add strings.
      Dim rw As ResourceWriter = New ResourceWriter("sample.resources")
      rw.AddResource("test1", "one")
      rw.AddResource("test2", "two")
      rw.AddResource("test3", "three")
      rw.AddResource("test4", "four")
      rw.AddResource("test5", 512341234)
      rw.Close()
      ...
   End Sub
End Class

NoteYou should assign this to an IResourceWriter to ensure that the code still works with other ResourceWriter classes that support the same interfaces.

The simplest way to retrieve the resources from a file is to iterate through them using the ResourceReader class. Building on the previous code, the minimum code necessary to enumerate the written resources is the following (which is taken from the same ResWrite.cs and ResWrite.vb program files):

Listing 3a. Iterating with ResourceReader (ResWrite.cs)

      ...
      // Iterate through the resources.
      IResourceReader rr = new ResourceReader("sample.resources");
      IDictionaryEnumerator de = rr.GetEnumerator();
      while (de.MoveNext()) {
            Console.WriteLine(de.Key + " " + de.Value);
      }
      rr.Close();
      ...

Listing 3a. Iterating with ResourceReader (ResWrite.vb)

      ...
      ' Iterate through the resources.
      Dim rr As ResourceReader = New ResourceReader("sample.resources")
      Dim de As IDictionaryEnumerator = rr.GetEnumerator()
      While de.MoveNext()
         Console.WriteLine((de.Key.ToString() + " " + de.Value.ToString()))
      End While
      rr.Close()
      ...

In this small example, you first created a ResourceReader for the same .resources file that you previously created. As you did when writing the resources, you assigned this to an IResourceReader for greater flexibility. You then used a DictionaryEnumerator to walk through the resources, printing the resource name and corresponding value to the console.

Although directly using a ResourceReader allows you to enumerate the resources, it does not allow you to directly retrieve specific resources by specifying a named entry. You can use the powerful ResourceManager in the section Retrieving Resources Using Code to accomplish this.

See Also

Image Resources | Packaging Resources | Retrieving Resources Using Code | Resources Summary | Appendix A: Additional Resource Information | Appendix B: Resource Tools