Saturday, May 2, 2009

Code generation for a COM wrapper assembly

For my last post, I needed some quick and dirty code generator. Basically, I've a COM Iterop assembly full with interfaces I need to wrap with a specified template.

The following code works, but still needed some handwork (like hand coding the ref parameters). Use it on your own risk ;)


using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.IO;

namespace CodeGeneration
{
class Program
{
static Dictionary<string, string> keywordType;

static void Main(string[] args)
{
FillKeywordType();

Assembly interop = Assembly.Load(@"Tridion.ContentManager.Interop.cm_tom");
foreach (Type t in interop.GetTypes())
{
//Console.WriteLine(t.Name);
if (t.Name.StartsWith("_"))
{
WriteOut(t, t.Name.Replace("_",string.Empty));
}
}
Console.ReadLine();
}

private static void FillKeywordType()
{

keywordType = new Dictionary<string, string>();
keywordType.Add("System.String", "string");
keywordType.Add("System.Void", "void");
keywordType.Add("System.Int32", "int");
keywordType.Add("System.DateTime", "DateTime");
keywordType.Add("System.Boolean", "bool");
keywordType.Add("System.Object", "object");
}

private static void WriteOut(Type t, string className)
{
Console.WriteLine("Info of {0}", t.Name);

using (StreamWriter writer = new StreamWriter(string.Format("D:\\Work\\DisposableOut\\{0}.cs", className) ))
{

WriteHeader(writer, className);


foreach (MethodInfo mi in t.GetMethods())
{
if (!(mi.Name.StartsWith("get_") || mi.Name.StartsWith("set_") || mi.Name.StartsWith("let_")))
{
string methodSig = string.Format("{1} {0}", mi.Name, GetTypeName(mi.ReturnType.Name, mi.ReturnType.Namespace));
bool isVoid = (GetTypeName(mi.ReturnType.Name, mi.ReturnType.Namespace)=="void");
List<string> parameters = new List<string>();
List<string> parameterNames = new List<string>();
foreach (ParameterInfo pi in mi.GetParameters())
{
parameters.Add(string.Format("{1} {0}", pi.Name, GetTypeName(pi.ParameterType.Name, pi.ParameterType.Namespace)));
parameterNames.Add(pi.Name);
}
string parameter = string.Join(", ", parameters.ToArray());

writer.Write(@"public {0} ({2})" + Environment.NewLine +
@" {{" + Environment.NewLine +
@" checkNotDisposed();" + Environment.NewLine +
@" {5}com{1}.{3}({4});" + Environment.NewLine +
@" }}" + Environment.NewLine + Environment.NewLine,
methodSig, className, string.Join(", ", parameters.ToArray()), mi.Name, string.Join(", ", parameterNames.ToArray()),
isVoid?string.Empty:"return ");
}
}

foreach (PropertyInfo pi in t.GetProperties())
{
writer.Write(@"public {0} {1} {{" + Environment.NewLine, GetTypeName(pi.PropertyType.Name, pi.PropertyType.Namespace), pi.Name);
if (pi.CanRead)
{
//get
writer.Write(@" get {{" + Environment.NewLine +
@" checkNotDisposed();" + Environment.NewLine +
@" return com{1}.{0};" + Environment.NewLine +
@" }}" + Environment.NewLine ,
pi.Name, className);
}
if (pi.CanWrite)
{
//set
writer.Write(@" set {{" + Environment.NewLine +
@" checkNotDisposed();" + Environment.NewLine +
@" com{1}.{0} = value;" + Environment.NewLine +
@" }}" + Environment.NewLine,
pi.Name, className);
}
writer.Write("}" + Environment.NewLine + Environment.NewLine);
}

WriteFooter(writer);
writer.Flush();
writer.Close();
}
}

private static string GetTypeName(string name, string nameSpace)
{
string typeName = string.Format("{0}.{1}", nameSpace, name);
if (keywordType.ContainsKey(typeName))
{
return keywordType[typeName];
}
return typeName;
}

private static void WriteFooter(StreamWriter writer)
{
writer.Write(@" #endregion" + Environment.NewLine +
@" }" + Environment.NewLine +
@"}" + Environment.NewLine);
}

private static void WriteHeader(StreamWriter writer, string className)
{
StringBuilder fileHeader = new StringBuilder();
fileHeader.AppendFormat(@"using System;{0}", Environment.NewLine);
fileHeader.AppendFormat(@"using System.Collections.Generic;{0}", Environment.NewLine);
fileHeader.AppendFormat(@"using System.Text;{0}", Environment.NewLine);
fileHeader.AppendFormat(@"using System.Runtime.InteropServices;{0}", Environment.NewLine);
fileHeader.AppendFormat(@"using Tridion.ContentManager.Interop.TDS;{0}", Environment.NewLine);
fileHeader.AppendFormat(@"{0}", Environment.NewLine);
fileHeader.AppendFormat(@"namespace DisposableTridion{0}", Environment.NewLine);
fileHeader.AppendFormat(@"{{{0}", Environment.NewLine);
fileHeader.AppendFormat(@" public class {1} : DisposableBase {0}", Environment.NewLine, className);
fileHeader.AppendFormat(@" {{{0}", Environment.NewLine);
fileHeader.AppendFormat(@" private Tridion.ContentManager.Interop.TDS.{1} com{1};{0}", Environment.NewLine, className);
fileHeader.AppendFormat(@"{0}", Environment.NewLine);
fileHeader.AppendFormat(@" public {1}(Tridion.ContentManager.Interop.TDS.{1} {2}){0}", Environment.NewLine, className, className.ToLower());
fileHeader.AppendFormat(@" {{{0}", Environment.NewLine);
fileHeader.AppendFormat(@" com{1} = {2};{0}", Environment.NewLine, className, className.ToLower());
fileHeader.AppendFormat(@" }}{0}", Environment.NewLine);
fileHeader.AppendFormat(@"{0}", Environment.NewLine);
fileHeader.AppendFormat(@" ~{1}(){0}", Environment.NewLine, className);
fileHeader.AppendFormat(@" {{{0}", Environment.NewLine);
fileHeader.AppendFormat(@" Dispose(false);{0}", Environment.NewLine);
fileHeader.AppendFormat(@" }}{0}", Environment.NewLine);
fileHeader.AppendFormat(@"{0}", Environment.NewLine);
fileHeader.AppendFormat(@" protected override void DisposeMembers(){0}", Environment.NewLine);
fileHeader.AppendFormat(@" {{{0}", Environment.NewLine);
fileHeader.AppendFormat(@" DisposableBase.ReleaseComObject(com{1});{0}", Environment.NewLine, className);
fileHeader.AppendFormat(@" }}{0}", Environment.NewLine);
fileHeader.AppendFormat(@"{0}", Environment.NewLine);
fileHeader.AppendFormat(@" #region _{1} Members{0}", Environment.NewLine, className);

writer.Write(fileHeader.ToString());
}
}
}

No comments: