Using T4 Templates to generate custom strongly-typed code in Visual Studio


Strongly typed code rocks. Easy as that. Reduces bugs, and makes your developments more productive and efficient. We all know that.
One example of strong-typing inside Visual Studio: resource files are parsed by default with the ResXFileCodeGenerator tool, which generates automatic properties in C# files, that give us strongly-typed access to strings.
That’s cool, by I there’s a lot of customization capabilities there missing. For instance, ResXFileCodeGenerator generates internal classes by default, and this is not always desirable. Many people struggled around this in the past, so in Visual Studio 2008 a new custom tool was introduced: PublicResXFileCodeGenerator: the same one than before, but building public classes. Cool again, but still missing many things…
So, how to customize the code generation process?

Option 1: Write your own tool

You can write a tool that mimics the behavior of ResXFileCodeGenerator, and you can install it within the Visual Studio (so you can select your ResX files to be parsed with it). It´s not too complicated, but you need to develop a separate installation project, to be able to install it within VStudio. You can find an example here.
To be honest, I don´t like the idea of having to write the extension in a different project, needing to go there for every change, recompiling, re-installing, etc. Besides that, this approach means having one single tool for every resX files you want to parse, and therefor, the tool needs to be generic enough to give support for every use case you have.
One last inconvenient, is that as far as I know, a tool like this cannot act in several files at a time. That means that it will generate a code file for each resource file. It’s impossible to generate ONE code file for SEVERAL resource files.
Seems that I´m too lazy today for all of that, so I searched for other solutions, and found one that I really like: T4 templates

Option 2: Write a T4 Text Template

A T4 Text Template is “a mixture of text blocks and control logic that generate a text file”. In other words, it’s a piece of code that will generate a text file and will include it in your Solution (below the .tt file itself). This text file, pretty well can be a source code file, so this way we can automatically generate code for the solution, with all the power to customize it.
I have been studying them for a while, and I can tell you that they are really powerful. Some relevant aspects around them:
  1. They are text files (with .tt extension), that are included INSIDE your solution, so no need to keep them in a separate project, and no need to build a setup project to install them.
  2. This .tt files are, by default, parsed by the custom tool: TextTemplatingFileGenerator
  3. They can operate on several project files at a time, not only one, generating if you want ONE code file, for SEVERAL resource files.
  4. They don´t need to be installed or distributed in any form. Simply add them to your solution
  5. Changes in the Template don’t mean to go to a different solution, rebuilding and re-installing
  6. They can be written in both C# or VisualBasic.
  7. When they are parsed, the generate a code file below the Template (see below), with the same name as the template itself:
image
  1. They are usually parsed as soon as they are modified and re-saved.
  2. Because the modification and installation process is so simple, and because you can have if you want a different T4 Template for each resX file, you can have as many versions of the templates as you wish. Each one covering different needs. And that is cool !
Any disadvantages? Visual Studio integration
By now, Visual Studio offers no integration for T4 files. That means that by default you get no syntax highlighting, no intellisense, etc.
But this can be fixed by using one of the T4 integration extensions for VStudio out there. I have tested three of them:
  • Tangible T4 Editor: Honestly, I couldn’t get it to work. I installed it, apparently with no error, but it didn’t work. And I already started this post by saying I´m too lazy today, so I tested other solutions that installed fine at first try:
  • Clarius Visual T4: It installed just fine and added syntax highlighting and intellisense to T4 files. Unfortunately, it made my Visual Studio 2010 Ultimate freeze for about 10 seconds from time to time. So I decided to try a different option.
  • Deviart T4: It installed fine, and works pretty well. The syntax highlighting gets messed from time to time, but nothing serious. Just re-opening the file fixes it. It’s fast, and I like it. It’s the clear winner. And it’s free!
image

Some basic concepts about developing T4 templates

Developing a T4 template is pretty straightforward, if you have some experience with .Net. We are not going to explain here all the coding aspects about T4 templates, as it is extremely clearly explained here and here.
However, it’s a bit meesy the first time you see one, how code blocks are mixed with plain text blocks, especially if you don´t have an extension installed that gives you syntax highlighting.
So, first thing you should understand is that T4 templates mix parts of text that will simply be copied to the generated file (Text Blocks), and others that are code blocks to control the logic of the generation (Code Blocks). In Deviart T4, you will see the following highlighting:
  1. Text blocks, copied directly to the destination file (grayed out):
image
As I mentioned, whatever you write here will be directly copied to the destination file. No matter what it is. It won´t be validated by the tool, just copied. You are responsible of writing something that makes sense, and that won’t generate compiling errors.
  1. Code blocks (surrounded by <# … #> and similar):
image
These code blocks are parsed by the tool and executed. They are validated by the compiler, just like any other piece of code you write (that means that will generate compiling errors as usually). In the previous example, the code block is writing a “}” symbol to the output file, using the WriteLine method (se next chapter for more info).

Different ways to output text to the destination file

We already seen some of them, but basically, you have three different ways of outputting text:
1.- Put a Text Block in your template (like in the previous chapter).
2.- Invoke the WriteLine method inside a Code Block. Like in the example of previous chapter, anywhere you call WriteLine(“…”) from within a code block, will write that text line to the destination file.
3.- Mixing both Code Blocks and Text Blocks, like in the following example:
image
In this example, the header Text Block (grayed out) will only be copied if insertWarningHeader == true. This means that flow control of code blocks affect the output of plain text blocks too.
Please note that you need to “end” the Code Block by using the “#>”, and therefor the text inside the braces will be identified as a Text Block. Then, re-open a code block, just to put the final brace “}” of the IF statement. Separating it into two different Code Blocks doesn’t prevent the IF from doing its job…

Other useful kinds of Code Blocks

As you can see, the <# … #> labels define the start and end of code blocks that should be parsed and evaluated. Anything outside those labels is considered text blocks. There are other kinds of code blocks, as explained here:
  • Expression code blocks (<#= … #>): They evaluate an expression, and convert the result to string. Some examples:
    1. <#= 2 + 3 #> … will output a “5”
    2. <#= numberOfEntries * 2#> … Where numberOfEntries is a valid variable on that scope, will output the result of the addition.
    3. etc.
  • Class feature code blocks (<#+ … #>): Allow to define properties or helper methods. They can be defined in separate files. The following example defines the property RootNamespace and the helper method EmitEnum, available in all the template.
image
  • Importing namespaces is also very easy, you just need to put in the top of the file statements like the following:
<#@ import namespace="System.Xml" #>
I think that there’s not too much magic in here, so I won’t bore you with more detail. Everything is really simple to follow, and is really well explained in the above links, so I guess the best way to show a real T4 Template is with an example!

Example: Custom strong-typed access to resources with a T4 template

What we need

In this example, we will used the mentioned T4 templates to give a full-featured, strong-typed access to strings in resource files. I did it to meet my own needs, but using it as a starting point, it will very easy for you to adapt it to your own.
The goal is to be able to customize the following aspects directly from the resX file:
  • Access modifier of the class: public, private, internal
  • Namespace where the class is defined
  • Generate (if wanted), an enumeration with all the keys of the entries
  • Modify the return type of the properties. Does this make any sense? Yes (read below).
  • Allow ResX files to use Conditional Compilation:
    1. It would be fantastic if we could specify different values for strings, depending on conditional compilation symbols
    2. And it would be even greater, if we could specify different return types, depending on the same conditional compilation symbols.

Does it make any sense to modify return types?
In my scenario, it does. I’ll explain it, so you can see one example. Then it’s up to you to decide if that’s useful also in other situations…
I was writing a piece of code, related to 3D graphics, that I wanted to run in both Windows Phone and Android. That code has contents (bitmaps, etc), which are identified differently in Windows Phone (XNA) projects, and Android.
In the first one, contents are identified with Asset Names, which are strings. In the second one, contents are identified with Integer IDs. In fact, Android automatically generates a class like the ones we are creating here to give strong-type access to those integers.
Well, I wanted to centralize the loading of contents, so it was obvious that I would need to unify content identification with my own IDs. I simply didn’t want to have #if #endif blocks all around my code.
Question is, that I can write two versions of methods like LoadTexture(), one for each platform, and keeping the specifics inside the Content Repository, but the problem is that Android identifies contents with a different type (ints instead of strings), and that makes my code end up with a different interface for each version. Something like this:
#if(ANDROID)
        public static void LoadTexture(int pResourceID)
        {
        }
#elif(WINDOWS_PHONE)
        public static void LoadTexture(string pAssetName)
        {
        }
#endif
I have no problem with writing two versions of the method (that’s inevitable). But having two different interfaces is bad. Really bad.
Why? Because then, every single point in my code where I use this method will need a #if #endif code block too. And I hate that. I want this contents repository to expose a single interface. How do we achieve that?
If both platforms used strings to identify contents, I could create a table to map my own resource identifiers to that ones. But Android uses ints. And what is worse, they are automatically generated. I can see what IDs Android gave to a content, but I cannot guarantee that the ID will be consistent over time, as it’s generated by an automatic tool. In addition to that, I would need to maintain that table by hand, what is horrible and very bug prone.
Mmmmmhhh…
Seems that the only solution is writing code, with methods or properties that map my own resource IDs to: string assets in the case of XNA, and resource IDs in the case of Android. Something like:
#if(ANDROID)
        public static int Button1
        {
            get
            {
                return Resource.Drawable.Button1;
            }
        }
#elif(WINDOWS_PHONE)
        public static string Button1
        {
            get
            {
                return @"Contents\Textures\UI\Button1";
            }
        }
#endif
Having a repository like this, would allow me to eliminate the #if #endif blocks when calling methods like LoadTextures, as I could use: LoadTextures ( Respository.Button1 );
If we are compiling to ANDROID, Button1 will return an int and LoadTextures() will expect an int, so no problem. If we are compiling to Windows Phone, both will give and expect a string. Everything fine again.
The problem with that is that a single project can have hundreds, or thousands of resources, an maintaining the file manually can be a nightmare. If only it could be done automatically…
That’s where the variable return type of my template kicks in. It will give us precisely that, with the particularity that when on ANDROID (being the return type an int), the template will not insert string, but a call to the Android Repository.
This way, I get rid of having to deal manually with Android int IDs, and just work with their strong-typed names.
See below for more…

The implementation

The behavior of the template we have developed, to achieve all of this is:
  • It is designed to be placed inside your projects, just by the file it will process. It has to be in the same folder and needs to have the same name. So, if you want to process the file Textures.resx, you will end up with something like this in your solution:
image
Note 1: You can easily modify it to parse all the ResX files it finds in the project at once, but this time I needed it to work this way.
Important Note 2: To avoid duplicity of generated code, and compilation errors, when you add the template to a resource file, you should disable the default parsing of that ResX file, by removing the default custom tool (ResXFileCodeGenerator) and by setting BuildAction = None.
  • It will generate strong-typed properties to access all the strings it finds in the resX file
  • It can be instructed to generate an enumerate with all the keys in the file too
  • It will automatically generate the well formatted XML comments for the properties
  • It supports some special keywords (entries starting by “#C#_”), to allow customizing the generation process:
    1. CT4_ACCESS_MODIFIERS (public, private, internal): By default, the generated class will be public, but you can include this entry to modify this behavior. You can set the following values: public, private or internal.
image
    1. CT4_OVERRIDE_NAMESPACE (namespace name): By default, the class will be in the default namespace of the project, but you can include this entry to override that behavior, setting the desired namespace in the value of the entry:
image
  1. CT4_GENERATE_ENUM (enum name): If this entry is included, the template will create an Enumeration with all the key names of the ResX file, and also an special version of the GetResourceString() method, accepting as parameter one of those enumerations. You can specify the name of the enumeration in the Value field.
image
  1. CT4_DEFAULT_RETURNTYPE (string, int, etc): Allows to specify the default return type for all properties. The default return type if string.
image
  1. CT4_CONDITIONAL_COMPILATION_SYMBOLXX (Symbol Name): Allows to use conditional compilation inside the resource files. To do so, you must first identify what conditional compilation symbols are used in your project. In this example, we will have two of them: WINDOWS_PHONE, and ANDROID. So, we will create two entries to let the generator know about them, like the following:
image
  1. CT4_CONDITIONAL_RETURNTYPE: If conditional compilation is being used, it allows to specify a different return type for each conditional symbol, with following syntax:
@COND_SYMBOL1:type_1;@COND_SYMBOL2:type_2 …
Where COND_SYMBOLXX is one of the conditional compilation symbols defined before, and type_XX is the return type desired for that symbol.
The following example a string return type for WINDOWS_PHONE, and an integer return type for ANDROID:
image

Once we have configured the generation process with the control entries, it’s time to put some data there. A normal string entry is entered as usual, with unique name, a value, and a comment if you want to. How to include conditional compilation entries?
Using conditional compilation in string entries
The name and the comment of the entry are the same as in normal ones. It’s in the Value where we put the information needed, very much like when defining specific return types for each conditional compilation. The syntax is:
@COND_SYMBOL1:value_1;@COND_SYMBOL2:value_2 …
Where COND_SYMBOLXX is one of the conditional compilation symbols defined before, and value_XX is the string value desired for that symbol.
So, the following example:
image
Will generate the following code:
   66         ///<summary>
   67         ///Button 1 image asset name or ID
   68         ///</summary>
   69         #if(WINDOWS_PHONE)
   70              public static string Button1 { get { return "Content\Textures\UI\button1"; } }
   71         #elif(ANDROID)
   72              public static int Button1 { get { return Resource.Drawable.app_Icon; } }
   73         #endif
Note that the generator also takes into account the Comment field, and that the return types and values for each version of the property are different. Also, in the case of Android, note that the get method makes a Call to the Android resource repository class, with the strongly-typed properties that access the IDs.

The template code

The template is based on this other one, but with a modified behavior to meet my own needs. The code is:
<#
//  ----------------------------------------------------------------------------------------------
//  Template: Generates C# code to give strongly-typed access to resource files
//  Author: Inaki Ayucar
//  Website: www.graphicdna.net
//  Based on the work of: http://blog.baltrinic.com
//  Links:
//          MSDN about developing T4 files: http://msdn.microsoft.com/en-us/library/bb126445.aspx
//                                          http://msdn.microsoft.com/en-us/library/dd820620.aspx
//  ----------------------------------------------------------------------------------------------
#>
<#@ template debug="true" hostspecific="true" #>
<#@ assembly name="System.Core" #>
<#@ assembly name="System.Xml" #>
<#@ assembly name="Microsoft.VisualStudio.Shell.Interop.8.0" #>
<#@ assembly name="EnvDTE" #>
<#@ assembly name="EnvDTE80" #>
<#@ assembly name="VSLangProj" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Text.RegularExpressions" #>
<#@ import namespace="System.Xml" #>
<#@ import namespace="Microsoft.VisualStudio.Shell.Interop" #>
<#@ import namespace="EnvDTE" #>
<#@ import namespace="EnvDTE80" #>
<#@ import namespace="Microsoft.VisualStudio.TextTemplating" #>
<#  // --------------------------------------------------------------------------------------------
    // Get global variables
    // --------------------------------------------------------------------------------------------
    var serviceProvider = Host as IServiceProvider;
    if (serviceProvider != null)
        Dte = serviceProvider.GetService(typeof(SDTE)) as DTE;
 
 
    // Fail if we couldn't get the DTE. This can happen when trying to run in TextTransform.exe
    if (Dte == null)
        throw new Exception("T4MVC can only execute through the Visual Studio host");
 
    Project = GetProjectContainingT4File(Dte);
 
    if (Project == null)
    {
        Error("Could not find the VS Project containing the T4 file.");
        return"XX";
    }
 
     AppRoot = Path.GetDirectoryName(Project.FullName) + '\\';
     RootNamespace = Project.Properties.Item("RootNamespace").Value.ToString();
    // --------------------------------------------------------------------------------------------
#>
// ---------------------------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
// ---------------------------------------------------------------------------------------------------
using System.Threading;
 
 
<#
try
{
        // We are storing in a List<ResourceEntry> (declared below) a list with all string entries
        // of all files found matching our search criteria
        AllEntries = new List<ResourceEntry>();
 
        // Entries starting with "CT4_", are declared as "control" entries, defining keywords or data
        // that will modify the source code generation behavior
        ControlEntries = new List<ResourceEntry>();
 
        // Find files on our project that match our search criteria (recursively), and store every
        // string entry on those files
        FindResourceFilesRecursivlyAndRecordEntries(Project.ProjectItems, "");
        AllEntries.Sort( new Comparison<ResourceEntry>( (e1, e2) => (e1.Path + e1.File +
                                 e1.ValidIdentifierName).CompareTo(e2.Path + e2.File + e2.ValidIdentifierName)));
 
        // Parse control entries
        string overrideNameSpace = "";
        string classAccessModifier = "public";
        string generateEnumName = "";
        string defaultReturnType = "string";
        Dictionary<string, string> returnTypesForConditionalCompilation = new Dictionary<string, string>();
        List<string> conditionalCompilationSymbols = new List<string>();
        List<string> conditionalCompilationSymbolsInValues = new List<string>();
        foreach(ResourceEntry entry in ControlEntries)
        {
            if(entry.OriginalName == "CT4_OVERRIDE_NAMESPACE")
            {
                overrideNameSpace = entry.Value;
                continue;
            }
            if(entry.OriginalName == "CT4_ACCESS_MODIFIERS")
            {
                classAccessModifier = entry.Value.ToLower();
                if(classAccessModifier != "public" &&
                   classAccessModifier != "private" &&
                   classAccessModifier != "internal")
                    Error("Invalid CT4_ACCESS_MODIFIERS found: Only public, private or internal are allowed");
                continue;
 
            }
            if(entry.OriginalName == "CT4_GENERATE_ENUM")
            {
                generateEnumName = entry.Value;
                continue;
            }
            if(entry.OriginalName.StartsWith("CT4_CONDITIONAL_COMPILATION_SYMBOL"))
            {
                conditionalCompilationSymbols.Add(entry.Value);
                conditionalCompilationSymbolsInValues.Add(string.Format("@{0}:", entry.Value));
                continue;
            }      
            if(entry.OriginalName.StartsWith("CT4_DEFAULT_RETURNTYPE"))
            {
                defaultReturnType = entry.Value;
                continue;
            }
            if(entry.OriginalName.StartsWith("CT4_CONDITIONAL_RETURNTYPE"))
            {
                returnTypesForConditionalCompilation.Clear();
                bool hasCondCompilation = StringValueHasCompilationSymbols(entry.Value,
                                                               conditionalCompilationSymbolsInValues);
                if(!hasCondCompilation)
                    Error("CT4_CONDITIONAL_RETURNTYPE entry found, but no conditional symbols were found in value");
 
                Dictionary<string, string> parts = SplitStringForConditionalCompilationSymbols(entry.Value,
                                                                 conditionalCompilationSymbolsInValues);
                foreach(string symbol in parts.Keys)
                    returnTypesForConditionalCompilation.Add(symbol, parts[symbol]);
                continue;
            }      
        }
 
        // Foreach string entry found, add it's code
        string currentNamespace = "";
        string currentClass = "";
        bool thisIsFirstEntryInClass = true;
        List<string> names = new List<string>();       
        for(int i=0;i<AllEntries.Count;i++)
        {
            ResourceEntry entry = AllEntries[i];
 
            var newNamespace = overrideNameSpace == "" ? RootNamespace: overrideNameSpace;
            var newClass = entry.File;
            bool namesapceIsChanging = newNamespace != currentNamespace;
            bool classIsChanging = namesapceIsChanging || newClass != currentClass;
 
            // Close out current class if class is changing and there is a current class
            if(classIsChanging && currentClass != "")
            {
                EmitNamesInnerClass(names);
                WriteLine("\t}");
            }
 
            // Check if there is a namespace change
            if(namesapceIsChanging)
            {
                // Close out current namespace if one exists
                if( currentNamespace != "" )
                    WriteLine("}");
 
                currentNamespace = newNamespace;
 
                // Open new namespace
                WriteLine(string.Format("namespace {0}", currentNamespace));
                WriteLine("{");
 
            }
 
            // Check if there is a class Change
            if(classIsChanging)
            {
                currentClass = newClass;
                WriteLine(string.Format("\t" + classAccessModifier + " class {0}", currentClass));
                WriteLine("\t{");
                thisIsFirstEntryInClass = true;
 
                // Only if the class changed, Emit code for the ResourceManager property and
                // GetResourceString method for the current class
                #>
                private static global::System.Resources.ResourceManager resourceMan;
 
                /// <summary>
                ///   Returns the cached ResourceManager instance used by this class.
                /// </summary>
                [global::System.ComponentModel.EditorBrowsableAttribute
                                               (global::System.ComponentModel.EditorBrowsableState.Advanced)]
                private static global::System.Resources.ResourceManager ResourceManager
                {
                    get
                    {
                        if (object.ReferenceEquals(resourceMan, null))
                        {
                            global::System.Resources.ResourceManager temp = new
                                              global::System.Resources.ResourceManager("
                <#=string.Format("{0}.{1}{2}", RootNamespace, entry.Path + "." + entry.File, entry.Type) #>",
                                                        typeof(<#=entry.File#>).Assembly);
                            resourceMan = temp;
                        }
                        return resourceMan;
                    }
                }
 
                /// <summary>
                ///   Returns the formatted resource string.
                /// </summary>
                [global::System.ComponentModel.EditorBrowsableAttribute
                                                (global::System.ComponentModel.EditorBrowsableState.Advanced)]
                private static string GetResourceString(string key, params string[] tokens)
                {
                    var culture = Thread.CurrentThread.CurrentCulture;
                    var str = ResourceManager.GetString(key, culture);
 
                    for(int i = 0; i < tokens.Length; i += 2)
                        str = str.Replace(tokens[i], tokens[i+1]);
 
                    return str;
                }
 
                <#
                if(generateEnumName != "")
                {
                #>/// <summary>
                /// Returns the formatted resource string, passing the enum value as parameter
                /// </summary>
                [global::System.ComponentModel.EditorBrowsableAttribute
                                           (global::System.ComponentModel.EditorBrowsableState.Advanced)]
                private static string GetResourceString(<#= generateEnumName.ToString() #> key, params string[] tokens)
                {
                    var culture = Thread.CurrentThread.CurrentCulture;
                    var str = ResourceManager.GetString(key.ToString(), culture);
 
                    for(int i = 0; i < tokens.Length; i += 2)
                        str = str.Replace(tokens[i], tokens[i+1]);
 
                    return str;
                }
 
                <#
                }
            }         
 
 
            // Write entry comment for property
            EmitEntryComment(entry, thisIsFirstEntryInClass);
 
            // Select all tokens between braces that constitute valid identifiers
            var tokens = Regex.Matches(entry.Value, @"{(([A-Za-z]{1}\w*?)|([A-Za-z_]{1}\w+?))?}").
                                                                       Cast<Match>().Select(m => m.Value);       
            if(tokens.Any())
            {
                var inParams = tokens.Aggregate("", (list, value) => list += ", string " + value)
                    .Replace("{", "").Replace("}", "");
                if(inParams.Length > 0 ) inParams = inParams.Substring(1);
                var outParams = tokens.Aggregate("", (list, value) => list += ", \"" + value +"\", " +
                                                                value.Replace("{", "").Replace("}", "") );
 
                WriteLine(string.Format("\t\tpublic static string {0}({1}) {{ return
                          GetResourceString(\"{0}\"{2}); }}",  entry.ValidIdentifierName, inParams, outParams));
 
                names.Add(entry.ValidIdentifierName);
            }
            else
            {
                // Detect if entry has conditional compilation symbols
                string entryValue = entry.Value;
                bool hasCondCompilation = StringValueHasCompilationSymbols(entryValue,
                                                                   conditionalCompilationSymbolsInValues);
 
                if(!hasCondCompilation)
                    EmitProperty(defaultReturnType, entry.ValidIdentifierName, entryValue, "", false, false);
                else
                {
                    // If has conditional compilation, generate one versino for each symbol
                    Dictionary<string, string> valuesForCondCompilation = SplitStringForConditionalCompilationSymbols
                                                              (entryValue, conditionalCompilationSymbolsInValues);
                    int c = -1;
                    foreach(string key in valuesForCondCompilation.Keys)
                    {
                        c++;
                        string rtype = defaultReturnType;
                        if(returnTypesForConditionalCompilation.ContainsKey(key))
                            rtype = returnTypesForConditionalCompilation[key];
 
                        EmitProperty(rtype, entry.ValidIdentifierName, valuesForCondCompilation[key],
                                                          key, c == 0, c == valuesForCondCompilation.Count - 1);
                    }
                }
                names.Add(entry.ValidIdentifierName);
            }
 
            thisIsFirstEntryInClass = false;
    }
 
 
    // Close out the current class when done, writing down the names
    if(currentClass != "")
    {
        EmitNamesInnerClass(names);
 
        if(generateEnumName != "")
            EmitEnum(names, generateEnumName);
 
        names.Clear();
 
        WriteLine("\t}");
    }
}
catch(Exception ex)
{
    Error(ex.ToString());
}
#>
 
<#
    // Only close the namespace if I added one
    if(AllEntries.Count > 0)
        WriteLine("}");
#>
 
 
 
<#+ // ------------------------------------------------------------------------------
    // Class feature control block:
    // Remarks: Identified by the #+ mark, allows to define variables, methods, etc
    // ------------------------------------------------------------------------------
    const string Kind_PhysicalFolder = "{6BB5F8EF-4483-11D3-8BCF-00C04F8EC28C}";
    bool AlwaysKeepTemplateDirty = true;
    static DTE Dte;
    static Project Project;
    static string AppRoot;
    static string RootNamespace;
    static List<ResourceEntry> AllEntries;
    static List<ResourceEntry> ControlEntries;
 
    /// <Summary>
    /// FindResourceFilesRecursivlyAndRecordEntries
    /// Remarks: Searches in the files of our project, for one that is in the same folder than this
    /// template, has the same name, and has the extension ".resx". If found, takes all string entries
    /// on it and stores them in the AllEntries list.
    /// </Summary>
    void FindResourceFilesRecursivlyAndRecordEntries(ProjectItems items, string path)
    {
        // I wanna take care about file path and name, but not about extension, so take everything but the extension
        string aux = Path.GetExtension(Host.TemplateFile);
        string T4FileWithoutExtension= Host.TemplateFile.Substring(0, Host.TemplateFile.Length - aux.Length);
 
        foreach(ProjectItem item in items)
        {       
 
            if(Path.GetExtension(item.Name) == ".resx")
            {
                    string itemFileName = item.FileNames[0];
                    if(itemFileName == null)
                            continue;
                    aux = Path.GetExtension(itemFileName);       
                    itemFileName = itemFileName.Substring(0, itemFileName.Length - aux.Length);       
 
                    // If the file path and name (without extension) is not equal to the template file, continue
                    if(itemFileName.ToLowerInvariant() != T4FileWithoutExtension.ToLowerInvariant())
                        continue;
 
                    RecordEntriesInResourceFile(item, path);
 
                    // We only want to parse one file. This should never happen, but if we find 2 files, just quit
                    break;
            }
            if(item.Kind == Kind_PhysicalFolder)
                FindResourceFilesRecursivlyAndRecordEntries(item.ProjectItems, path+"."+item.Name);
        }
    }
    /// <Summary>
    /// RecordEntriesInResourceFile
    /// Remarks: For a given file, takes all its entries and stores them in the AllEntries list.
    /// </Summary>
    void RecordEntriesInResourceFile(ProjectItem item, string path)
    {
        //skip resource files except those for the default culture
        if(Regex.IsMatch(item.Name, @".*\.[a-zA-z]{2}(-[a-zA-z]{2})?\.resx"))
                return;
 
        var filePath = (string)item.Properties.Item("FullPath").Value;
        var xml = new XmlDocument();
        xml.Load(filePath);
        var entries = xml.DocumentElement.SelectNodes("//data");
 
        var parentFile = item.Name.Replace(".resx", "");
        var fileType = Path.GetExtension(parentFile);
        if(fileType != null && fileType != "")
            parentFile = parentFile.Replace(fileType, "");
 
        foreach (XmlElement entryElement in entries)
        {
            var entry = new ResourceEntry
            {           
                Path = path != "" && path != null?path.Substring(1):"",
                File = MakeIntoValidIdentifier(parentFile),
                Type = fileType,
                OriginalName = entryElement.Attributes["name"].Value,               
            };
 
            var valueElement = entryElement.SelectSingleNode("value");
            if(valueElement != null)
                entry.Value = valueElement.InnerText;
 
            var commentElement = entryElement.SelectSingleNode("comment");
            if(commentElement != null)
                entry.Comment = commentElement.InnerText;
 
            if(entry.OriginalName.StartsWith("CT4_"))
                ControlEntries.Add(entry);
            else
            {
                // Parse the name into a valid identifier
                entry.ValidIdentifierName = MakeIntoValidIdentifier(entry.OriginalName);
 
                AllEntries.Add(entry);
 
            }
        }
    }
    /// <Summary>
    /// MakeIntoValidIdentifier
    /// Remarks:
    /// </Summary>
    string MakeIntoValidIdentifier(string arbitraryString)
    {
        var validIdentifier = Regex.Replace(arbitraryString, @"[^A-Za-z0-9-._]", " ");
        validIdentifier = ConvertToPascalCase(validIdentifier);
        if (Regex.IsMatch(validIdentifier, @"^\d")) validIdentifier = "_" + validIdentifier;
        return validIdentifier;
    }
    /// <Summary>
    /// ConvertToPascalCase
    /// Remarks:
    /// </Summary>
    string ConvertToPascalCase(string phrase)
    {
        string[] splittedPhrase = phrase.Split(' ', '-', '.');
        var sb = new StringBuilder();
 
        sb = new StringBuilder();
 
        foreach (String s in splittedPhrase)
        {
            char[] splittedPhraseChars = s.ToCharArray();
            if (splittedPhraseChars.Length > 0)
            {
                splittedPhraseChars[0] = ((new String(splittedPhraseChars[0], 1)).ToUpper().ToCharArray())[0];
            }
            sb.Append(new String(splittedPhraseChars));
        }
        return sb.ToString();
    }
    /// <Summary>
    /// EmitNamesInnerClass
    /// Remarks:
    /// </Summary>
    void EmitNamesInnerClass(List<string> names)
    {
        if(names.Any())
        {
            WriteLine("\r\n\t\tpublic static class Names");
            WriteLine("\t\t{");
            foreach(var name in names)
                WriteLine(string.Format("\t\t\tpublic const string {0} = \"{0}\";", name));
            WriteLine("\t\t}");
        }
    }
    /// <Summary>
    /// EmitNamesInnerClass
    /// Remarks:
    /// </Summary>
    void EmitEnum(List<string> names, string pEnumName)
    {
        if(!names.Any())
            return;
 
        WriteLine("\r\n\t\tpublic enum " + pEnumName);
        WriteLine("\t\t{");
        foreach(var name in names)
            WriteLine(string.Format("\t\t\t{0},", name));
        WriteLine("\t\t}");
 
        names.Clear();       
    }
    /// <Summary>
    /// StringValueHasCompilationSymbols
    /// Remarks: Returns true if a conditional compilation symbol mark (@symbol:) is found in a string
    /// </Summary>
    bool StringValueHasCompilationSymbols(string pValue, List<string> pConditionalCompilationSymbolsInValues)
    {
        foreach(string symb in pConditionalCompilationSymbolsInValues)
        {
            if(pValue.Contains(symb))
                return true;
        }
        return false;
    }
    /// <Summary>
    /// SplitStringForConditionalCompilationSymbols
    /// Remarks: Splits a string (thas has been checked, and has conditional compilation symbols), and
    /// returns a dictionary where the keys are the conditional compilation symbols, and the values are
    /// the values of the string for that symbols.
    /// </Summary>
    Dictionary<string, string> SplitStringForConditionalCompilationSymbols(string entryValue,
                                                    List<string> pConditionalCompilationSymbolsInValues)
    {
        Dictionary<string, string> retValue= new Dictionary<string, string>();
        string[] parts = entryValue.Split(new char[1]{';'}, StringSplitOptions.RemoveEmptyEntries);
        foreach(string part in parts)
        {
            foreach(string symb in pConditionalCompilationSymbolsInValues)
            {
 
                if(part.StartsWith(symb))
                {
                    string origSymbol = symb.Remove(0, 1);
 
                    origSymbol = origSymbol.Remove(origSymbol.Length - 1 , 1);
 
 
                    string val = part.Remove(0, symb.Length);
                    retValue.Add(origSymbol, val);
                    break;
                }
            }
        }
        return retValue;
    }
    /// <Summary>
    /// EmitProperty
    /// Remarks: Writes down a property of the return type specified, name and value, and allowing
    /// to add a conditionalcompilationSymbol
    /// </Summary>  
    void EmitProperty(string pReturnType, string pPropertyName, string pPropertyValue,
                      string pConditionalCompilationSymbol, bool pIsFirstConditionalCompilation,
                      bool pIsLastConditionalCompilation)
    {
        bool hasCondCompilation = (pConditionalCompilationSymbol != null && pConditionalCompilationSymbol != "");
 
        // Write opening conditional compilation
        if(hasCondCompilation)
        {
            if(pIsFirstConditionalCompilation)
                WriteLine(string.Format("\t\t#if({0})", pConditionalCompilationSymbol));
            else WriteLine(string.Format("\t\t#elif({0})", pConditionalCompilationSymbol));
        }
 
        // Write property
        switch(pReturnType)
        {
            case "string":
                WriteLine(string.Format("\t\tpublic static {0} {1} {{ get {{ return \"{2}\"; }} }}",
                                        pReturnType, pPropertyName, pPropertyValue));
                break;
            default:
                WriteLine(string.Format("\t\tpublic static {0} {1} {{ get {{ return {2}; }} }}",
                                        pReturnType, pPropertyName, pPropertyValue));
                break;
        }
 
        // Close cond compilation
        if(hasCondCompilation && pIsLastConditionalCompilation)
            WriteLine("\t\t#endif");
    }
    /// <Summary>
    /// EmitEntryComment
    /// Remarks: Writes down an entry comment as a properly formatted XML documentation comment
    /// </Summary>
    void EmitEntryComment(ResourceEntry entry, bool thisIsFirstEntryInClass)
    {
            // Insert the entry comment (if any) in a proper XML documentation format
            if(entry.Comment != null)
            {
                if(!thisIsFirstEntryInClass)
                    WriteLine("");                 
                WriteLine(string.Format("\r\n\t\t///<summary>\r\n\t\t///{0}\r\n\t\t///</summary>",
                                         entry.Comment.Replace("\r\n", "\r\n\t\t///")));
            }
            else WriteLine("");
    }
    /// <Summary>
    /// GetProjectContainingT4File
    /// Remarks:
    /// </Summary>
    Project GetProjectContainingT4File(DTE dte)
    {
 
        // Find the .tt file's ProjectItem
        ProjectItem projectItem = dte.Solution.FindProjectItem(Host.TemplateFile);
 
        // If the .tt file is not opened, open it
        if (projectItem.Document == null)
            projectItem.Open(Constants.vsViewKindCode);
 
        if (AlwaysKeepTemplateDirty) {
            // Mark the .tt file as unsaved. This way it will be saved and update itself next time the
            // project is built. Basically, it keeps marking itself as unsaved to make the next build work.
            // Note: this is certainly hacky, but is the best I could come up with so far.
            projectItem.Document.Saved = false;
        }
 
        return projectItem.ContainingProject;
    }
    /// <Summary>
    /// Struct: ResourceEntry
    /// Remarks: Stores information about an entry in a resource file
    /// </Summary>
    struct ResourceEntry
    {       
        public string Path { get; set; }
        public string File { get; set; }
        public string Type { get; set; }
        public string OriginalName { get; set; }
        public string ValidIdentifierName { get; set; }
        public string Value { get; set; }
        public string Comment { get; set; }
    }  
#>

Et voilĆ  ! An input and output example

The above template, applied to the following input:
image
Produces the following output class:
// ------------------------------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
// ------------------------------------------------------------------------------------------------------
using System.Threading;
 
 
namespace GDNA.PencilBurst
{
public class Textures
{
        private static global::System.Resources.ResourceManager resourceMan;
 
        /// <summary>
        ///   Returns the cached ResourceManager instance used by this class.
        /// </summary>
        [global::System.ComponentModel.EditorBrowsableAttribute
                              (global::System.ComponentModel.EditorBrowsableState.Advanced)]
        private static global::System.Resources.ResourceManager ResourceManager
        {
            get
            {
                if (object.ReferenceEquals(resourceMan, null))
                {
                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager
                                      ("GDNA.PencilBurst..Textures", typeof(Textures).Assembly);
                    resourceMan = temp;
                }
                return resourceMan;
            }
        }
 
        /// <summary>
        ///   Returns the formatted resource string.
        /// </summary>
        [global::System.ComponentModel.EditorBrowsableAttribute
                                           (global::System.ComponentModel.EditorBrowsableState.Advanced)]
        private static string GetResourceString(string key, params string[] tokens)
        {
            var culture = Thread.CurrentThread.CurrentCulture;
            var str = ResourceManager.GetString(key, culture);
 
            for(int i = 0; i < tokens.Length; i += 2)
                str = str.Replace(tokens[i], tokens[i+1]);
 
            return str;
        }
 
        /// <summary>
        /// Returns the formatted resource string, passing the enum value as parameter
        /// </summary>
        [global::System.ComponentModel.EditorBrowsableAttribute
                                              (global::System.ComponentModel.EditorBrowsableState.Advanced)]
        private static string GetResourceString(eTextureIDs key, params string[] tokens)
        {
            var culture = Thread.CurrentThread.CurrentCulture;
            var str = ResourceManager.GetString(key.ToString(), culture);
 
            for(int i = 0; i < tokens.Length; i += 2)
                str = str.Replace(tokens[i], tokens[i+1]);
 
            return str;
        }
 
 
        ///<summary>
        ///Button 1 image asset name or ID
        ///</summary>
        #if(WINDOWS_PHONE)
        public static string Button1 { get { return "Content\Textures\UI\button1"; } }
        #elif(ANDROID)
        public static int Button1 { get { return Resource.Drawable.app_Icon; } }
        #endif
 
        public static class Names
        {
            public const string Button1 = "Button1";
        }
 
        public enum eTextureIDs
        {
            Button1,
        }
    }
 
}
 
 
 
 

Other use cases

The possibilities are almost endless. You don´t need to stick to Resource Files (ResX) only. You can do this operations with almost anything. For example:
  • You can write a T4 Template for a “Contents” projects, that searches for Textures or Bitmaps in the project, and generates a Class that strong-types the names and/or paths of those textures. Creating your own Content Manager.
  • You can generate your own classes to give strong-type access to your Data-Sets, in a totally customized way.
  • Or you can generate a class that bases it’s strong type access in an enumeration, instead properties, something like the following:
internal class TexturesByEnum
    {
        private static global::System.Resources.ResourceManager resourceMan;
 
        /// <summary>
        ///   Returns the cached ResourceManager instance used by this class.
        /// </summary>
        [global::System.ComponentModel.EditorBrowsableAttribute
                                        (global::System.ComponentModel.EditorBrowsableState.Advanced)]
        private static global::System.Resources.ResourceManager ResourceManager
        {
            get
            {
                if (object.ReferenceEquals(resourceMan, null))
                {
                    global::System.Resources.ResourceManager temp =
                                                     new global::System.Resources.ResourceManager
                                                     ("GDNA.Render.Repository.Textures", typeof(Textures).Assembly);
                    resourceMan = temp;
                }
                return resourceMan;
            }
        }
 
        /// <summary>
        /// Returns the formatted resource string, passing the enum value as parameter
        /// </summary>
        [global::System.ComponentModel.EditorBrowsableAttribute
                                          (global::System.ComponentModel.EditorBrowsableState.Advanced)]
        private static string GetResourceString(eTextureIDs key, params string[] tokens)
        {
            var culture = Thread.CurrentThread.CurrentCulture;
            var str = ResourceManager.GetString(key.ToString(), culture);
 
            for (int i = 0; i < tokens.Length; i += 2)
                str = str.Replace(tokens[i], tokens[i + 1]);
 
            return str;
        }
 
        public enum eTextureIDs
        {
            Button1,
            Button2,
        }
 
        ///<summary>
        /// Indexed access to class
        ///</summary>
        public static string this[eTextureIDs id]
        {
            get
            {
                    return GetResourceString(id);
            }
        }
    }
 
This way, access to resources would be:
string aux = Textures[eTextureIDs.Button1];
 
instead of…
 
string aux = Textures.Button1;
As you can see, the customization possibilities are huge, and the examples countless.
So use your imagination !!
Cheers !

Ramblings about the excellent Windows Media Center

Today, I was trying to setup a Windows Media Center Extender, to be able to see my movies (stored in my PC) through my XBox in the living room. In theory, it´s easy, but you can get into some troubles I´d like to point, just in case that might help you…

You can get some basic knowledge about Media Center extenders here.

First, try to connect your XBox with the PC, through Settings->Network->Connection to computer. If the connection is established successfully, you probably won´t have any problem configuring the Media Center Extender. But if you have problems, check:

1.- That your router supports Multicast Filtering, as some routers, like the Cisco EPC3825 (the one I was trying first), seem to have problems with that. In fact, in the settings dialogs of that router, you won´t find any option about Multicast Filtering. I can tell you that I tried every single possibility for a couple of hours with that router, and no luck. I switched to a different one (from Linksys), and everything worked like a charm…

2.- If your router is supposed to work with this feature, make sure you have enabled the mentioned “Filter Multicast” option (probably available in the Security settings tab of the router), and also that you have enabled the uPnP (probably in the Management settings tab of the router).

3.- If still have problems, you can check your Firewall settings to search for the needed open ports and so on… You can read more here.

One you have properly linked your PC and XBox 360, you can start the Windows Media Center on your PC, to choose what folders you will be sharing.

Some tips about folder structures, in order to see the covers of the movies, and additional info:

1.- Put each movie in a separate folder, as WMC will look this way for additional info for each movie

2.- If you want to manually download a cover for a movie or video, you just need to put the picture in the movie folder, with the name “folder.jpg”. WMC will load it automatically.

3.- If you want to put additional information, like movie specs, genre, etc, you should add some DVDID XML files with a certain format that will help WMC identifying the movie. You can download those files from http://dvdxml.com or even better, use one of the available metadata managers out there. I have tried YAMMM and works pretty well.

4.- If your XBox is downloading the movie covers and info again and again, each time you enter the Windows Media Center, or if it takes long to recover the covers, etc, that´s probably because you don´t have indexed the shared folders on your PC. Just make sure that the Indexing Service is installed and enabled (Start->Control Panel->Programs and Features->Turn on/off Windows features->Indexing Service), and also make sure that the shared folders for the movies are added to the index (Rightclick->properties->advanced->allow to add this folder to the index).

Some tips about YAMMM

1.- It´s a Windows Service, so don´t expect any User Interface, except for setting up the application. It’s run in background, monitoring the folders you tell it to for changes, and downloading automatically the info and covers.

2.- It expects movies to be in separate folders, and users folder’s name (not file’s name) to identify what movie you are talking about. If it doesn´t identify what movie it is, it won´t download anything. If it does, it can automatically rename the folder and movie files (with a more standard name, if you indicate it to do so), and will start downloading.

3.- YAMMM won´t find the correct movie if you don´t use the original movie name for the folder name. So forget any any translated version.

4.- To help YAMMM finding it, you can include the year of the movie, like this: “American Gangster (2007)”. That will help, a lot…

5.- If your movie is divided into several files (part 1, part 2, etc), YAMMM will automatically create a playlist for them, so WMC will identify them as a single movie. By default, after doing this you will see that WMC adds multiple entries for your movie: one for the playlist, and one for each part your AVI or DVD is divided into. In order to hide the parts, and live only the playlist, you can rename the AVI parts like: “video 1.avi” to “video 1.avi2”. This way, WMC won´t identify that part as a movie, and the reference file (playlist) will still work. (You should make sure that the playlist has modified the reference names too, by simply opening it with the WordPad).

Handling big files in Visual Studio Setup Projects


If you use Visual Studio to make your Setup projects, you probably noticed a very annoying and long lasting limitation of Visual Studio / Windows Installer, which is supposed to be fixed always in future versions. It´s nothing else than file size.
Setup projects do not handle well big files. In this post, I’ll show you how to workaround those problems:

Scenario 1: your files are big, but not that big

The first problem you will face when including big files in a setup project is a build error saying something like “Not enough storage is available to complete the operation”.
As mentioned here, If you handle files of a few hundreds of Megabytes, you can workaround this by:
  1. In the project, add a fake small file that has the same name as the large file.
  2. In the project properties page, set to installer to Package as Loose Uncompressed files.
  3. Build.
  4. Copy the full-sized large files to the build location.
In other words, you will fool the installer by inserting fake small files with the same names, and leaving them outside the MSI, so you can overwrite them before distributing your installer with the real, bigger files. As Windows Installer just looks for the file names, it will think the files are Ok, and will install the big ones.
Quick-Tip: If it’s annoying for you to have all the installation files as “loose uncompressed files”, you can only leave as “loose uncompressed” those files to be overwritten, leaving the rest inside the installer or in CAB files, whatever you prefer. To do so, do not change the project´s property, but instead change the property PackageAs of those files to be overwritten. The default value is vsdpaDefault, which means “do as specified in the project properties”. If you change it to vsdpaLoose, those files will remain loose in the disk, no matter what the general behavior for the rest of the files is.
This workaround is fine, but it doesn’t work always, as it will also fail if you have very big files, of several GBs…

Scenario 2: your files are huge

If you are dealing with huge files, of several GBs, the previous workaround won´t work either. The setup project will compile fine, but Windows Installer will probably fail later. This time, the error is shown when installing the application, and it appears in the form of a “couldn’t access destination directory, check you have enough privileges to do so”… or something like that.
What can you do in those cases?

Option 1: Split your files into smaller ones

You can use a file splitting utility, like FFSJ, to split your files into parts. Then add those smaller files to your Setup Project and install normally. When installation is complete, you will need to deal with re-joining the parts back into the original file. FFSJ supports receiving commands from the command line, so you can easily do this with a Custom Action.
  • Insert FFSJ into your setup project (check copyright)
  • Add a “Commit Custom Action” that points to FFSJ
  • Mark the Custom Action as InstallerClass = False
  • Pass the following “Arguments” to the custom action:
"-Task=Join" "-Input=[TARGETDIR]\FILE_TO_JOIN.001" "-Output=[TARGETDIR]\OUTPUT_FILE.dat" –DeleteInput
This action will be executed once the installation is complete, and once all the files have been copied to the Target Dir. If you include the “-DeleteInput” parameter, original file parts will be deleted.
Pros of this workaround:
  1. All files are handled “inside” Visual Studio, but that won´t help much anyway, as the file copy progress is not as “fluid” as it should be
Cons of this workaround:
        • You need to split the file into parts and insert them in Visual Studio manually
        • Copyright issues with the file splitter may apply
        • Do not handle uninstallation, as Windows Installer will try to remove the original files (parts), which no longer exist

Option 2: Code an specific Custom Action

I´m not sure of this, but I know of no way to call system commands like “copy” from a Visual Studio custom action, so we will code a very simple C# program, that will handle some basic file operations for us, like copying and deleting files. 
  1. Create a new Visual Studio project of the type Windows –> Console Application
  2. In the class Program.cs, we will deal with some file operations. In our example, we will assume that the huge file we want to copy has the name “Contents.dat” (you can experiment here to make it fit your needs). So, for our example, we would paste some code like the following:
[STAThread]
        static int Main(string[] cmdLine)
        {
            string operation = cmdLine[0];
            string sourcePath, installPath, sourceFileName, destFileName;
 
            switch (operation)
            {
                case "Copy":                   
                    sourcePath = cmdLine[1];
                    installPath = cmdLine[2];
 
                    sourceFileName = System.IO.Path.Combine(sourcePath, "Contents.dat");
                    destFileName = System.IO.Path.Combine(installPath, "Contents.dat");
 
                    if (!System.IO.Directory.Exists(installPath))
                        return -1;
 
                    System.IO.File.Copy(sourceFileName, destFileName, true);
                    break;
                case "Delete":
                    installPath = cmdLine[1];
                    destFileName = System.IO.Path.Combine(installPath, "Contents.dat");
                    System.IO.File.Delete(destFileName);
                    break;
            }
 
            return 0;
        }
As you can see, this is a very basic code that expects some Command Line parameters, with the following syntax:
Parameter 0: Operation type [“Copy” or “Delete”, without the quotes].
If copying: Parameter 1: Source path where “Contents.dat” is located. Parameter 2: Destination path where we want to copy it
If Deleting: Parameter 1: Path to delete “Contents.dat” from.
            • Next, we compile the code and generate an EXE file
            • Insert that EXE file into your setup project
            • Now we just need to create a couple of Custom Actions in our setup project that point to that EXE file, like the following (note that they will be executed at installation Commit and at Uninstallation):
image
              • Mark your custom actions as InstallerClass = False
              • Change the Custom Action arguments like the following:
                            • Arguments for the Copy operation: Copy "[SOURCEDIR]\" "[TARGETDIR]\"
                            • Arguments for the delete operation: Delete "[TARGETDIR]\"
Quick-Tip: Variables that contain paths, like [SOURCEDIR] or [TARGETDIR] might contain spaces. By default, that would mean that each part of the path would be interpreted as separated arguments. In order to avoid that, we surround those variables with quotes (“”).
Quick-Tip 2: As explained here, Windows Installer automatically adds a trailing slash to variables like [TARGETDIR], so in order to avoid messing the arguments, you will need to put a \” at the end, instead of a single quote (“).
Quick-Tip 3: It is important to note the return value of the Custom Action, as it’s checked by Windows Installer to decide if the action was completed successfully. So, if it’s 0, everything went fine. If it’s –1, an error occurred and the installation will be cancelled. So it’s up to you if the file copy is vital for your installation or not. But if it is, you´d better be returning a “–1” in those cases, to interrupt the installation.
So what´s going on here?
Easy to guess: Windows Installer will call our custom action after when the installation finish is about to end (Commit), with the arguments we specified, that will make our EXE copy the huge files to the installation directory.
In order to properly handle application uninstallation, we added another call to the same custom action, but this time with different arguments that will make it remove the huge files copied from the installation directory.
Pros of this workaround:
  1. No need to split files
  2. No copyright issues (everything is home made)
  3. Handles uninstallation
  4. No need to create fake, smaller files to fool the installer
  5. The custom action created can be made generic, so you can re-use it as many times you want.
Cons of this workaround:
        • It would be much better if Visual Studio didn’t have this limitation, and we never needed to worry about this GuiƱo
So, I think option 2 is much better. In fact, is what I use.
Hope it helped.

Simax F1 Simulator

Today, we have released an introductory video of the next challenge we are facing here at Simax: take our technology to the F1 racing field.

In this case, we are developing a replica of the Renault R30: a 2.4L V8 engine which reaches 19.000 rpm and almost 900 hp, for less than 600 Kg… Awesome!

Hope you like it…

Battery charging problems on Samsung Focus (Windows Phone 7)

Yesterday, my Samsung Focus stopped working properly.

I plugged it to the wall for hours, the battery icon showed that it was plugged, but the battery level did not raise. If I unplugged the phone, an immediate message of “Battery critically low” appeared.

After reading some posts, I realized that the battery was in fact being charged, but the OS was not “reading” the battery level correctly.

In my case, as in many others, it was fixed by simply entering the Diagnostics mode of the Samsung Focus, to directly read the “actual” battery level. After that, everything is back to normality.

1.- To enter Diagnostics mode, open the phone keypad and enter: ##634#

2.- To access battery information (and others), type *#2*# in the next keypad that will appear.

And that´s all.

Silver Navigator 1.2 released !

Hi there!

Silver Navigator, ranking top downloads in many countries around the world, is ready for an update, as version 1.2 has just passed through the certification process in the Windows Phone Marketplace. So it´s ready for download!!

This new version includes:

  • Local Searches: hotels, restaurants, shops... (might not be available in all countries)
  • Map rotation
  • Voices volume increased
  • Some minor bug fixes
  • And much more…

You can follow Silver Navigator 1.2 here, and download it from this Zune Link.

ArtWork2_1000x800

Taking advantage of high-level C# features to make our 3D games API or platform independent

In the last few years, programming languages and development tools have evolved quite a bit. Visual Studio is a masterpiece nowadays, and things like Refactoring and Intellisense make our life much easier.
There are other cool features that can be now used in our code, and that are really appropriate to make our 3D engines API-Independent. I´m talking about Generics and Extension Methods.

What is API or platform multi-targeting?

Multi-targeting is writing a software (a game, for instance) that can run in different platforms or use different APIs. Of course, we should try to achieve this with the following constraints:
  • Avoid redundancy as much as possible (as we already saw that Duplicating is wrong).
  • If possible, introduce no performance overhead at all, or at least try to minimize it

When is multi-target necessary?


It is obviously necessary if your application is meant to be distributed for different platforms (XBox, PS3, PC, etc, for example). But making your software multi-target is also very recommendable in other situations, for example when you need to upgrade your technology to a newer version of an API.
For instance, imagine that DirectX11 just came out. You would like to take advantage of some new features of it, but cannot force all your clients to upgrade their graphics cards, so you still need to support DirectX10. The solution is to make your software support both DirectX10 and 11, with multi-targeting. In this article, we will use the case of targeting an application to two different render APIs: SlimDX and XNA.
If you already faced this problem before, you know it can be a serious one, especially if your software was not designed to support multi-targeting from the beginning, and you have API calls scattered all around your code. How do we make the change without needing to re-write the entire software from scratch?
Let’s explore the possibilities:

A macro-C++ approach

When using languages like C++, some people make multi-targeting using Macros:
  • Write all your game-logic code using your own MACRO-named types like: myMatrix4x4, myTexture, etc.
  • Write a header file for each platform, in which all that macros are declared:
#define myVector3 Microsoft::Xna::Framework::Vector3
#define myMatrix4x4 Microsoft::Xna::Framework::Matrix
But remember, MACROS ARE THE SOURCE OF ALL EVIL IN THE WORLD.
Macros easily grow in complexity. Specially if you start making multi-level macro calls. They make debugging and understanding the software a hell on Earth, and are extremely bug-prone, if you are not very careful. They have even been removed from modern languages like C#. So I totally discourage you to use this solution.
  • Pros:
      • Everything arranged for each platform at compilation: no performance penalty.
      • No design effort. Easy development
      • Resolved at compilation: no performance overhead
  • Cons:
      • Make debugging, tracing and maintenance of the software in general a hell in Earth
      • Very bug-prone
      • Not available in modern languages, like C#
      • In my opinion it’s against good practices in software. At least as long as a better solution exists.
      • Compilation of C++ projects which massively use macros can take years to complete, especially if macros are recursive
      • They don´t do the job for every case

The conditional compilation approach

As we have already seen, some parts of your code must be different for each platform, so an obvious and easy way to make your software multi-target is using conditional compilation.
This approach is supported in almost every language, and works by defining compilation constants in your project like: PLATFORM_XNA, or PLATFORM_SLIMDX. Then, each time you find an API-dependent code part, you do something like:
#if(PLATFORM_XNA)
...
#else
...
#endif

  • Pros:
      • Everything arranged for each platform at compilation: no performance penalty.
      • No design effort. Easy development
      • Available in all languages
  • Cons:
      • Ugly and un-elegant code
      • Uncomfortable to understand and trace
      • Your code will grow considerably (too much redundancy)
      • In my opinion it’s against good practices in software. At least as long as a better solution exists.

The layered approach

This is one of the usual approaches. It is related to software engineering more than to an specific language, and involves all the stages of development, since conception and first designs, to the final coding.
What it suggests is dividing your application in “layers”, keeping internal layers for the game-logic related issues, which do not depend on the API or platform at all, and making an external layer that will give output to all that logic, through the API. This way, when you need to target a different platform, only the external layer has to be rewritten.
This external layer, usually deals with things like Rendering, that’s why it’s very typical to find games out there with DLLs like: RendererDX9.dll, RendererDX10.dll, etc.
  • Pros:
      • Elegant
      • Easy to understand, trace and debug
      • Robust, not too bug-prone
      • Available in all languages
  • Cons:
      • It requires a big design effort
      • It can introduce a bit of performance overhead
      • It introduces redundancy of code and information, as some game states has to be stored in several layers
      • It’s sometimes not a feasible solution if the project is already written (the multi-target was not planned from the beginning), as it implies big structural changes.
      • Following this design will give your software a Library or API looking I personally don’t like, as it breaks a bit the consistency of classes, by separating tasks that conceptually should belong to a class into other assemblies. This is one of the points I personally disagree more of this approach. I prefer to keep this consistency, leaving all tasks related to an object inside it’s class. Just an example to show this:
You will end up with lines of code like:
RendererDX9.RenderModel(this);
Instead of the traditional:
this.Render();
Some people would say that rendering an object is not a task naturally belonging to that object. Well, as I said, this is a matter of personal preference, and I prefer the second approach. That’s why in next chapter we will try to make a multi-target system that follows it.

The inheritance approach

This approach is elegant as well (as the previous one). It also related to engineering and planning more to an specific language, and also involves many stages of the development.
Instead of dividing your software in layers, it relies mostly on Inheritance, through a very basic design for classes that are API-Dependant like the next example:
            • Model3DBase
                  • Model3DSlimDX
                  • Model3DXNA
It is quite obvious that we will put in the base class all the non API-dependent code, and the rest in the child classes. For example, the ToString() method has nothing to do with the platform the 3D model will be rendered in. So that code will be in the base class, avoiding rewriting it for each child.
Once we have all the classes divided for each version of the API, in the outer part of your software you just need to choose which kind of Scene to use. Something like: SceneSlimDX or SceneXNA.
This approach works, it’s elegant, easy to understand and trace, and keeps the consistency of classes, but it has a major drawback: for classes like this (a 3D Model), many many member variables and methods will be API-specific, so the amount of code in the base class will be much lower than in the child, dependent classes. This will force you to write a huge amount of duplicated code, and we already said that duplicating is wrong.
  • Pros:
      • Elegant
      • Easy to understand, trace and debug
      • Robust, not too bug-prone
      • Available in all languages
      • It keeps the consistency of classes, allowing us to put the Render method inside the Model3D class, instead of having to take it out to another class.
  • Cons:
    • It requires some design effort
    • It’s sometimes not a feasible solution if the project is already written (the multi-target was not planned from the beginning), as it implies big structural changes.
    • Splitting your types for each API won´t help reducing redundancy in higher code levels too (what will happen when we are going to use the model? which version will be use? Again conditional compilation?)
    • The biggest problem is the redundancy of code mentioned (many code parts will be repeated in the child classes)

So, which one is best?

Again, this is all a matter of personal preference.
Macros are discarded by themselves… too bug-prone, and not present in modern languages. In my opinion, best option is a combination of: a little bit of conditional compilation (in very few cases), and in some cases a bit of layered design too. But whatever we choose, all of them have the same problem: code redundancy.
If only we could reduce that code redundancy…

C# comes to save the day

.Net has been introducing improvements to software development since it’s conception. It saves you time. It saves you money. It saves you headaches. It saves you stress. In my opinion, that’s precisely the strong selling point of .Net.
Microsoft has succeeded in making programmers’ life easier, with no renounce to performance, efficiency or robustness
In the latest releases, .Net is going even further, introducing new ways of development that can, not only make your life easier, but also offer you the possibility to face old problems in new ways. This case is just an example.

Extension Methods

Many times, APIs are similar to each other. You will have textures, you will have 3D models, you will have vertices and faces. Even rendering methods will be probably similar. And it´s a pain having to add conditional compilation just for something like finding the number of vertices in a 3D model mesh:
#if(RENDER_XNA)
            int vertexCount = mMesh.NumVertices;
#elif(RENDER_SlimDX9)
            int vertexCount = mMesh.VertexCount;
#endif
Both XNA and SlimDX offer that information, but the name of the property changes. There are many many cases like this where code changes are just semantics, or just re-arranging stuff. And it´s a pity to add redundancy all around your code for such a simple thing.
We of course can put a “GetVertexCount” method or a “VertexCount” property in our Model3D class, but… What happens when we are working with simple Meshes (no access to our own Model3D type)? Conditional compilation again?
Not yet… Because Extension Methods can help here…

What are Extension Methods?

Extension Methods enable you to "add" methods to existing types without creating a new derived type, recompiling, or otherwise modifying the original type.
So, we can take the type "SlimDX.Direct3D9.Mesh”, or “Microsoft.Xna.Framework.Graphics.ModelMeshPart”, and add a method to it. Just like if we could modify its code.
This way, we are allowed to unify or standardize the interfaces of API-dependent types, to drastically reduce the need for conditional compilation, and therefore code redundancy.

How do they work?

Following what´s explained here, we can easily code the “GetVertexCount” method like this:
public static int GetVertexCount(this Microsoft.Xna.Framework.Graphics.ModelMeshPart pMesh)
{
     return pMesh.NumVertices;
}
 
public static int GetVertexCount(this SlimDX.Direct3D9.Mesh pMesh)
{
     return pMesh.VertexCount;
}
Note: You just need to add that method to a static class in your DLL that holds Extension Methods.
Having this, both XNA´s ModelMeshPart and SlimDX´s Mesh will offer the GetVertexCount method. With the exact same interface. So, any part of our code that wants to have this information won´t need to add conditional compilation nor redundancy anymore.
We can do similar stuff with many many differences between APIs: properties renamed or relocated, methods with different or re-arranged parameters, or even creating methods that exist in one API and not in the other.
The objective is to unify the interfaces of both APIs as much as possible.

What about performance?

We are adding a call to a method where there wasn’t any. So, in theory, we are adding a performance overhead. But here is where the Visual Studio compiler comes to help.
As you already know, there is a thing called Inlining that will help here. When your code is compiled, the compiler will replace any call to the GetVertexCount method with it´s real inner code. So no performance overhead is really added.
However, you should take care with Inlining, as there are several conditions for this to happen:
  • Methods that are greater than 32 bytes of IL will not be inlined.
  • Virtual functions are not inlined.
  • Methods that have complex flow control will not be in-lined. Complex flow control is any flow control other than if/then/else; in this case, switch or while.
  • Methods that contain exception-handling blocks are not inlined, though methods that throw exceptions are still candidates for inlining.
  • If any of the method’s formal arguments are structs, the method will not be inlined.
More info on Inlining: here, and here and here.

C# comes to save the day (II)

Generics

Since 2.0, .Net introduced Generics, a way to work with variables without specifying what type they are. This is especially useful for cases where the type of those variables is irrelevant. One of the direct and most useful examples that soon appeared is Generic Collections. The logic behind a List or Dictionary of things is the same, no matter what that “things” are.

How can Generics help out here?

Generics introduce two clear advantages:
  • Generics are resolved at compilation, so no performance overhead is introduced at all. In fact, Generics can imply some performance advantages, in certain cases. Read this article (Generics implementation chapter) for more information.
  • Generics will again dramatically reduce the Duplication and redundancy of information and code in our projects.

Reducing duplication even more, with generics

Apart from using Extension Methods, as we have seen in the previous chapter, we can reduce Conditional Compilation and code redundancy even more, with the use of Generics.
Many times, some parts of our code need to add conditional compilation just because types used are different on each API, but the operations performed on them don´t need to know what type they actually are. For instance, if we create a Material class, it will probably hold a list of textures, and the Texture type is API-dependent. Will we need to add conditional compilation every time we want handle that list of textures? Probably not.
Making the Material class to be generic, will allow us to work with Textures, without knowing if they actually are SlimDX or XNA textures:
public class Material<T_Texture>
{
     protected List<T_Texture> mTextures;
}

That reduces redundancy in the Material class, as any management of the List of textures can be done without knowing the type: adding or removing textures, accessing to them, etc.

What if we still need to perform an API-dependent operation in a generic class?

Sometimes, your classes won´t be purely generic, and still will need to perform some operations that are API-specific. In those cases, you can always check what the type of the generic T_Texture actually is.
Just like in the following example, where the generic type is checked to return one type of value or another:
 public static T GetRenderState<T>(this Microsoft.DirectX.Direct3D.Device pSrc, RenderState pState)           
        {
            if (typeof(T) == typeof(int))
                return (T)Convert.ChangeType(pSrc.GetRenderStateInt32((RenderStates)pState), typeof(T));
            else if (typeof(T) == typeof(float))
                return (T)Convert.ChangeType(pSrc.GetRenderStateSingle((RenderStates)pState), typeof(T));
            else if (typeof(T) == typeof(bool))
                return (T)Convert.ChangeType(pSrc.GetRenderStateBoolean((RenderStates)pState), typeof(T));
            else throw new System.ApplicationException("Generic Type invalid");
        }

Using the generic (Material) class

When the Material class is finished, we will probably want to use it in a Model3D class. We just need to do something like:
public class Model3D
{
    #if(RENDER_XNA)
         protected Material<Microsoft.Xna.Framework.Graphics.Texture2D> mMaterial;
    #elif(RENDER_SlimDX9)
         protected Material<SlimDX.Direct3D9.Texture> mMaterial;
    #endif
}

This way, we remove any conditional compilation or code redundancy from the Material class, and add it just a couple of times when declaring and instantiating the mMaterial variable.

Going even further with conditional #using statements

This is pretty obvious, but anyway it might help someone.
Many times, types have the same names in several APIs. For instance, the type VertexBuffer exists in: XNA, in SlimDX and in Managed DirectX.
For such cases, we can reduce conditional compilation and code redundancy even more, with #using statements at the beginning of each code file. Imagine we have a class XXX like the following:
public class XXX
{
    #if(RENDER_XNA)
        protected Microsoft.Xna.Framework.Graphics.VertexBuffer mVertexBuffer;
    #elif(RENDER_SlimDX9)
        protected SlimDX.Direct3D9.VertexBuffer mVertexBuffer;
    #endif
}

In that case, we are adding the conditional compilation just because the namespace of a type changes. It´s much better to add the conditional compilation just once in the #using statements, avoiding to spare them all through your code:
#if(RENDER_XNA)
    #using Microsoft.Xna.Framework.Graphics;
#elif(RENDER_SlimDX9)
    #using SlimDX.Direct3D9;
#endif

public class XXX
{
    protected VertexBuffer mVertexBuffer;
}

Using Generic’s constraints to reduce even more redundancies

We still didn’t mention other possibilities Generics have, like Constraints. Constraints are a way to tell the environment that, even when a type is Generic (like T_Texture), it meets certain constraints, like to have a constructor, or to inherit from a class or interface. Just an example:
public class Model3DBase<T_Material, T_Texture>
    where T_Material : MaterialBase<T_Texture>
{
        protected List<T_Material> mMaterials;

}
This makes an huge difference reducing duplication as now, even specifying no type for T_Material, we will be able to access all the properties and methods specified in MaterialBase.
Other examples:
Constraint Description
where T: struct The type argument must be a value type. Any value type except Nullable can be specified. See Using Nullable Types (C# Programming Guide) for more information.
where T : class The type argument must be a reference type, including any class, interface, delegate, or array type. (See note below.)
where T : new() The type argument must have a public parameterless constructor. When used in conjunction with other constraints, the new() constraint must be specified last.
where T : <base class name> The type argument must be or derive from the specified base class.
where T : <interface name> The type argument must be or implement the specified interface. Multiple interface constraints can be specified. The constraining interface can also be generic.
where T : U The type argument supplied for T must be or derive from the argument supplied for U. This is called a naked type constraint.
More on Constraints here.

Want to know more on Generics?

This magnificent article on generics will explain you more about this issue.

Conclusion

C# and .Net are offering new ways of facing old problems. This article tried to show how to take advantage of some new features like Generics and Extension Methods in a very old problem: API-independent 3D engines.
So, we took those new functionalities and combined them with old approaches of facing this issue, to come with a new, improved implementation, that has a basic objective: reduce code redundancy.
Hope you liked it.
Cheers!