WinRes is a .Net SDK tool that localization specialists can use to localize Forms. It hosts designers for the Form and components on it, and also a property grid, using which you can localize a Form and save it to the appropriate culture. The MSDN link above has general information about how to use this tool.

The cool thing about WinRes is that it can visually represent a Form based on just the information contained in a resource file (.resx or .resources). It can bring up a Form at design time and allow you to modify its localizable properties - all without access to the source code. How does it do that? The resource file has information in it about the Type of the components present on a Form. WinRes uses this information to dynamically create those components and their designers. It then initializes the (Localizable) properties on those components using the values serialized (I will probably talk another day about how we do the serialization) into the resource file by Visual Studio. Once the localizer has made the appropriate modifications, it serializes the new set of property values into a culture specific resource file (like Form1.fr.resx for French) that can be built into a satellite assembly. To learn more about Localization in general, here are some useful articles.

The ability to design and localize a Form visually without access to the source code is nice, but there are currently some limitations to what WinRes can do. I have fielded many questions about WinRes from both internal and external customers. I think documenting the limitations of the WinRes and the common issues you might run into maybe of some benefit. This blog is as good a place as any to do this, so here goes.

WinRes TroubleShooting

First of all, having a basic knowledge of the resource file format can be extremely useful when you run into problems. Resource files can be either in XML (.resx) or binary (.resources) format. The .resx format is more human-readable, so if you have a .resources file that you wish to look at, use the ResGen tool to convert it to a .resx. Now, open the .resx file in notepad. You will find the schema definition and some other stuff in the header. That stuff is not so interesting, so I won't describe it here. The rest of the .resx file is made up of "data" nodes. Each data node represents one localizable property in the dialog. Lets look at a couple of data nodes in a simple resx file for a Form that contains a Button:

<data name="button1.Size" type="System.Drawing.Size, System.Drawing, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
    <value>75, 23</value>
</data>

<data name="button1.Text">
    <value>button1</value>
</data>

The first node has the name "button1.Size", so looks like it represents the Size property of a component called button1. The type attribute represents, not surprisingly, the full name of the Type of this property. The value node contains a string representation of value of the Size property, which is in this case: (Width = 75, Height = 23). SImilarly, the second node above represents the Text property on button1. There is no Type information, so by default, this means that the property is of type String.

Okay, but what is button1? This information is conveyed by the following "special" properties, prefixed with the ">>":

<data name="&gt;&gt;button1.Name">
    <value>button1</value>
  </data>
  <data name="&gt;&gt;button1.Type">
    <value>System.Windows.Forms.Button, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
  </data>
  <data name="&gt;&gt;button1.Parent">
    <value>$this</value>
  </data>
  <data name="&gt;&gt;button1.ZOrder">
    <value>0</value>
  </data>

These are special because they convey information about what button1 represents. The Type property tells us that button1 is actually a Windows Forms Button control. Its parent is "$this", which represents the Form being localized. The ZOrder value helps determine the order in which this component is placed on this Parent control relative to its siblings. The Name, ofcourse, is the name assigned to this instance of the Button control by the VS designer. With the above information, you should be able to decipher most of the contents of the .resx file.

Okay, now we are ready to look at some of the possible reasons for getting a 'Red X' (error) in WinRes when you load a Form. Unfortunately, the error messages that WinRes displays are currently often cryptic. So, when an error occurs, you should open the .resx file in notepad and take a look.

  • The most common problem is due to a current limitation of WinRes that it needs to be able to instantiate all the components on the Form. To instantiate a particular component, WinRes needs to load the assembly that contains it. WinRes needs the assembly to be present either in the Global Assembly Cache (GAC) or the same folder as WinRes.exe (search your file system for this file to locate where WinRes.exe is present - its usually in [dir where VS is installed]\SDK\[version]\Bin. All the framework assemblies should be in the GAC already, so WinRes should be able to instantiate components in them. However, if you have user controls or third party controls on your Form and their assemblies aren't in the GAC, you should either install them in the GAC or copy them to the WinRes folder.
  • Make sure that controls with a common parent have unique "ZOrder" values. If two or more controls with a common parent have the same ZOrder, WinRes is likely to fail to load the dialog, since it doesn't know in what order to place the controls.
  • Sometimes, the resx may contain incorrect Type information for one or more of the components in the Form. Make sure that the Type's name and assembly information is correct and complete. If not, WinRes will fail to load the Type.
  • The "name" attribute represents a property on a component and is always of the form "component.Property" (with the exception of the ">>" prefix on the special properties). Make sure that the names in your resx are in that format. Also, make sure that all the 4 special properties noted above are present for each component. WinRes needs those! 
  • Make sure you are using the version of WinRes compatible with the assemblies you are localizing. For example, if your assemblies are built against v1.1 of the .NET Framework, use the WinRes.exe that came with v1.1 framework SDK. If not, you might run into weird versioning issues. 
  • Another issue you might run into is this: when you have a combobox or listbox with items in it and you bring up the dialog with this control in WinRes, WinRes may not populate the control with those items. Further, if you add items to it through WinRes and save the localized resource, the localized items will not get picked up at runtime. It is, unfortunately, a limitation in WinRes currently that it is not able to handle collections (like the comboBox.ItemsCollection) correctly. The workaround is to not pre-populate the control with items, but do so at runtime with localized strings.

That is all I can think of at this time. I will post more information when I can.