Welcome to MSDN Blogs Sign in | Join | Help

WinRes

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. 

Published Thursday, August 21, 2003 1:02 AM by rprabhu
Filed under:

Comments

# WinRes: Improvements in Whidbey

Friday, February 18, 2005 4:41 AM by Cool Client Stuff

# WinRes: Improvements in Whidbey

Friday, February 18, 2005 4:44 AM by Cool Client Stuff

# WinRes

Friday, November 25, 2005 6:20 AM by Kunal shah
Hi Prabhu,

Though I am too late too read your article as its posted way back in 2003.

Any start is a good start in learning..

So read your article..Pretty good..Well collected material. And also quite different from what I have seen in few others.

Keep Posting Good Articles.

Regards

Kunal shah
kunalshah83@gmail.com

# re: WinRes

Friday, November 25, 2005 11:43 PM by rprabhu
Thanks Kunal - glad you found it useful.

# re: WinRes

Saturday, January 07, 2006 4:22 PM by Veselin Barakov
Hi,

Why the type is stored in the resource file? It seems quite silly!

And now, if you have localized form in .Net 1.1 how you will open in .Net 2.0 Forms designer? You cannot.

Have you considered those issues? How do you suppose all the localized forms in 1.1 willbe migrated to 2.0? Manually?

Regards,

Veselin

# re: WinRes

Wednesday, January 18, 2006 7:04 PM by rprabhu
You can open v1.1 localized forms in v2.0 form designer in VS. VS has a specialized type resolution implementation that will resolve the types correctly. Once you make a change to a form, the resx will automatically be updated to v2.0 references.

As for WinRes, it is recommended to use the same version of WinRes.exe as the .NET version you are targeting.

# re: WinRes

Monday, June 05, 2006 4:56 PM by Larry Smith
Hi Prabhu,

Many thanks. I've been searching high and low for weeks trying to find info on how "Winres.exe" does its job as well as the special symbols used by the form designer (>>, $this, etc.). I need to replicate what "Winres.exe" does in my own code by converting a ".resx" file back to its form. Is there a simple way to do this using some existing class or can I safely read the ".resx" file and gather up all the form's properties manually. If the latter, are the special symbols officially documented somewhere or otherwise dependable? Any links would be welcome. I assume I can just find all controls in the file in a WYSIWYG fashion (i.e., the form's properties are always of the form ">>$this.PropertyName" possibly preceded with ">>" and all controls will ultimately have a ">>ControlName.Parent" property whose Value is "$this). Can you confirm this. Thanks very much.

# re: WinRes

Wednesday, June 07, 2006 3:29 PM by rprabhu
Larry: You should be able to use the ResXResourceReader and ResXResourceWriter classes to process resx files. Regarding the special '>>' properties, I don't know if they are documented, but I think third party software already exists today that depend on it. I would recommend logging a bug in MSDN Product Feedback to request that they be documented (if not already).

# re: WinRes

Tuesday, June 13, 2006 7:50 PM by Larry Smith
Hi Prabhu,

Thanks very much for the feedback. I don't believe those symbols are documented after a painstaking search so will contact MSDN Product Feedback as you suggested. Thanks again.

# re: WinRes

Wednesday, June 14, 2006 2:53 PM by Larry Smith
Hi Prabhu,

One other important question for you if you don't mind. I just read your other blog entitled "How does the Windows Forms designer in Visual Studio load a Form" (currently at http://blogs.msdn.com/rprabhu/archive/2004/12/12/280823.aspx) and am now unsure if the approach I suggested earlier is correct. Note that I'm fairly new to .NET but otherwise a very experienced C/C++ developer (20+ years on MSFT platforms and very comfortable with C#). In a few sentences or less since I don't want to take too much of your time (I can do the leg work), could you simply point me in the "right" direction for doing the following. I'm writing an Add-In that needs to pull out all *localized* forms in a solution and bundle them up so they can be displayed elsewhere (for viewing purposes only on machines without Visual Studio present). Is it appropriate to simply bundle up all localized (form-based) ".resx" files accordingly and ship them out. My app will then re-generate these forms based on this ".resx" info. Or should I be investigating "CodeDomProvider" and cousins as you discussed in the above link. Or should I be using reflection to find and gather up all forms in the solution. I'm really not sure which method (or hybrid thereof) would be recommended and some guidance would be greatly appreciated (I've done lots of research already). Also note that when "InitializeComponent()" is created in the IDE, it automatically sets certain other (non-localized) properties in-code such as "UseVisualStyleBackColor" on button controls. How would I then know to do this myself if, say, I simply re-generate the form using the bundled ".resx" files approach (akin to what "WinRes.exe" does). Again, your assistance would be greatly appreciated (I can't find adequate info elsewhere after a painstaking search). Thanks again.

# re: WinRes

Wednesday, June 14, 2006 4:25 PM by Larry Smith
Sorry Raghavendra, but I just realized I've been addressing you by your last name (mea culpa). My apologies :)

# re: WinRes

Monday, June 19, 2006 6:49 PM by rprabhu
Larry: In general, I would say simply enumerating the resx files in the solution and using them should work. After all, WinRes too only has the resx files to work with, and does not have know about any other changes that might be in InitializeComponent. The theory is that any changes relevant to localization should be in the resx anyway, so other changes in code should not matter to localizers.

Note though that your resx parser tool will need access to the assemblies/types referenced in the resx, just like WinRes, in order to instantiate them.

Anyway, I must mention that I have moved to a different team in Microsoft around 8 months ago, so I am quite out of touch with this stuff. I am not sure who the current owner of WinRes is, but you could start by contacting Brad Abrams (blogs.msdn.com/brada), who might be able to point you to the right person.

# re: WinRes

Wednesday, June 21, 2006 8:17 AM by Larry Smith
Ok, your comments make me more comfortable that at least I'm on a suitable path (it's always reassuring to have someone on the inside help validate things). I'll contact Brad Adams as suggested however just in case there's a better way to do this now (a new class perhaps). Thanks for the feedback (appreciated).

# re: WinRes

Friday, July 07, 2006 12:23 PM by Larry Smith
Hi Raghavendra,

Quick follow-up that perhaps you can help me with (though you're on another team now however). I recently discovered that ".resx" files can't be completely relied on to re-generate a form since not all information about all controls is captured. For instance, if a menu is attached to a dialog then the ".resx" file doesn't capture any "parent" info for each menu item so you don't know which item belongs to which menu. A similar situation exists for "DataGridView" controls where no (parent) info exists linking individual columns back to their "DataGridView" control. The bottom line is that you can't reconstruct menus that may be attached to a form nor any "DataGridView" controls based on resx files alone (and perhaps other controls exist with the same problem). Therefore, AFAIK, the only way to completely capture a form at design-time is to parse "InitializeComponent()" itself. Is there anyway to do this presently (i.e., does a class exist to capture the same form info now wrapped in this function). Thanks for your help.

# re: WinRes

Tuesday, July 11, 2006 2:56 PM by rprabhu
Larry: Yes, you are right. There are limitations to how much of the form you can reconstruct from a resx file. For localization purposes, this has not proved as much of a limitation, since localizers typically just like to look at the high level layout of the form, not specifics like menu items and tree view nodes. Also, the new 'auto-layout' features in VS 2005 obviate the need for doing detailed localization in terms of relayout.

You *could* parse InitializeComponent to better layout the form, but I think this would be pretty hard to get right (I would know, I used to own the parsing/generating of this code in VS :-))and isn't really supported.

Not sure I understand your scenario, but if your forms are already compiled, why not reflect over their assemblies and actually instantiate them?

# re: WinRes

Friday, July 28, 2006 11:23 AM by Larry Smith
Thanks for the feedback (sorry for the delay responding). Unfortunately, reflecting over the assemblies doesn't appear to be viable since the programmer may have added additional code after the call to "InitializeComponent()". This code may not be runnable in the development environment (or is potentially unsafe to run there) so it can't be relied on. Parsing "InitializeComponent()" isn't viable either for the reasons you mentioned and a programmer would have to write their own language parser anyway (which isn't feasible as you noted). The only way I can think of is to perhaps copy "InitializeComponent()" into a temporary ".cs" file on the fly (using some temporary class), and then I can compile and run it. This is unwieldy however (and incredibly ugly) but there doesn't appear to be any other option. I think the situation is something that should be addressed by MSFT however even if relatively few developers actually require this functionality. It may be low priority but the programming model remains incomplete IMO. There's simply no clean way to extract a complete form from a project but it should be relatively easy to add this functionality and I already made my own recommendations to product feedback several weeks ago (on the surface it should be doable with no backward compatibility issues). Anyway, unless you have any other last suggestions, thanks again for all your help (appreciated).

# re: WinRes

Friday, February 16, 2007 12:33 PM by Yayu

Hi Rhagavendra,

You said "There are limitations to how much of the form you can reconstruct from a resx file. For localization purposes, this has not proved as much of a limitation, since localizers typically just like to look at the high level layout of the form, not specifics like menu items and tree view nodes". I am localizer and this is not 100% true, one localizer's task is to ensure there is not duplicated HK in the localized assembly and using winres its very difficult to achieve this. For example, if you have a dialog with a couple of tabs or more when you clik on winres button check HK it will show as error duplications in strings located on different tabs, what its not real HK duplicate. This is a pain for us. Thanks.

# re: WinRes

Saturday, February 17, 2007 3:37 PM by rprabhu

Yayu: I think WinRes was designed to cover the basic and common localization scenarios. For more advanced stuff, there are good third party tools available as well.

That said, if you have any feedback or suggestions, please submit it through the MSDN Product Feedback page so it can be tracked properly (I am no longer working in this area).

Thanks!

# Why Name, Parent, Type, &amp; ZOrder in the resx file? | keyongtech

New Comments to this post are disabled
 
Page view tracker