Tag Archives: xml schemas

How to: create your own ‘Custom Tool’ (AKA: XMLcode generator)

What is a Custom Tool?

Here are some statements which describe a custom tool:

It’s a file generator

It makes code-behind files

It extends Visual Studio

It’s stored in a ComVisible DLL file

It uses the Registry

Quoted from ‘Custom Tools Explained‘ 

Steps to create custom tool

  1. Create Dll project for custom tool (AKA: Repository.CodeGenerator).
    1. Add a new ‘RepositoryCodeGenerator.reg’ file with the below content.
    2. Add your ‘Repository.xsd’ XSD file.
    3. Add your new ‘Generator.cs’ class file (see the content of ‘Generator.cs’).
    4. Make sure your project is COM visible.

[csharp title=”<h4>Content of Generator.cs</h4>”]
using Microsoft.VisualStudio.TextTemplating.VSHost;
using System.Runtime.InteropServices;

namespace Repository.CodeGenerator
{
[Guid("11111111-1111-1111-1111-111111111111")]
public class Generator : BaseCodeGenerator
{
protected override byte[] GenerateCode(string inputFileName, string inputFileContent)
{
return new MyRepositoryBuilder(MyGeneratorErrorCallback).MyGenerateRepositoryCode(inputFileContent);
}

public override string GetDefaultExtension()
{
return ".Designer.cs";
}
}
}
[/csharp]
[text title=”<h4>Post buiild event of Repository.CodeGenerator</h4>”]

xcopy /y "$(ProjectDir)Repository.xsd" "$(DevEnvDir)….xmlschemas"
xcopy /y "$(ProjectDir)Repository.xsd" "$(SolutionDir)MyRuntime$(OutDir)"
call "$(DevEnvDir)….VCvcvarsall.bat"
regasm /codebase "$(TargetPath)"
regedit /s "$(ProjectDir)RepositoryCodeGenerator.reg"

[/text]
[text title=”<h4>Content of RepositoryCodeGenerator.reg</h4>”]

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINESOFTWAREMicrosoftVisualStudio10.0Generators{00000000-0000-0000-0000-000000000000}RepositoryCodeGenerator2.0]
"GeneratesDesignTimeSource"=dword:00000001
"CLSID"="{11111111-1111-1111-1111-111111111111}"
<em id="__mceDel">
[/text]
[csharp title=”<h4>Content of MyGenerateRepositoryCode</h4>”]
public byte[] GenerateRepositoryCode(string inputFileContent, bool withAutoGenCode)
{
try
{
ValidateRepository(@"Repository.xsd", inputFileContent);

StringReader stringReader = new StringReader(inputFileContent);
StringWriter codeWriter = new StringWriter();
XDocument xDocument = XDocument.Load(stringReader, LoadOptions.SetLineInfo);

if (xDocument.Root != null)
{
CodeDomProvider codeDomProvider = new CSharpCodeProvider();

CodeNamespace buildNamespace = BuildNamespace(xDocument.Root);

CodeGeneratorOptions codeGeneratorOptions = new CodeGeneratorOptions
{
BracingStyle = "C",
BlankLinesBetweenMembers = false
};
if (withAutoGenCode)
{
CodeCompileUnit codeCompileUnit = new CodeCompileUnit();
codeCompileUnit.Namespaces.Add(buildNamespace);
codeDomProvider.GenerateCodeFromCompileUnit(codeCompileUnit, codeWriter, codeGeneratorOptions);
}
else
{
codeDomProvider.GenerateCodeFromNamespace(buildNamespace, codeWriter, codeGeneratorOptions);
}

}
return Encoding.UTF8.GetBytes(codeWriter.ToString());
}
catch (Exception e)
{
// handle exception …
}
return null;
}
[/csharp]

 

[csharp title=”<h4>Example 'BuildNamespace function'</h4>”]
internal CodeNamespace BuildNamespace(XElement root)
{
XAttribute rootAttrib = root.Attribute("Name");
CodeNamespace ns = null;
if (rootAttrib != null && rootAttrib.Value != "")
{
XAttribute versionAttr = root.Attribute("Version");
if (versionAttr != null)
{
double ver;
if (double.TryParse(versionAttr.Value, out ver))
{
version = ver;
}
}

ns = new CodeNamespace(rootAttrib.Value);
foreach (Type type in basicTypes)
{
ns.Imports.Add(new CodeNamespaceImport(type.Namespace));
}
BuildClass(ns, null, root);
}
return ns;
}
[/csharp]

… and so on…

Remarks

  • Replace ‘00000000-0000-0000-0000-000000000000’ with a newly generated GUID.
  • replace ‘11111111-1111-1111-1111-111111111111′ with newly generated GUID.

Resources

Custom Tools Explained – CodeProject.

XSD -> Classes Generator Custom Tool (radically new and extensible) – Daniel Cazzulino’s Blog.

BaseCodeGenerator Class (Microsoft.VisualStudio.TextTemplating.VSHost).