changeset 6:e640ca67b819

Added extended COM interop code generator for interfaces and proxies
author Ivo Smits
date Fri, 06 May 2011 04:02:43 +0200
parents 00fb4879d273
children a7650e26195f
files InteropCodeGen/ComInteropInterfaceGenerator.cs InteropCodeGen/ComInteropProxyGenerator.cs InteropCodeGen/InteropCodeGen.csproj InteropCodeGen/LibraryInformation.cs InteropCodeGen/Program.cs InteropCodeGen/XidlParser.cs
diffstat 6 files changed, 806 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/InteropCodeGen/ComInteropInterfaceGenerator.cs	Fri May 06 04:02:43 2011 +0200
@@ -0,0 +1,103 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.IO;
+
+namespace VBoxSDK {
+	class ComInteropInterfaceGenerator {
+		public TextWriter Output { get; private set; }
+		public Boolean IncludeInheritedMembers { get; set; }
+		public Boolean IncludeComAttributes { get; set; }
+		public Boolean ComInterfaceTypeIDispatch { get; set; }
+		public String TypeModifiers { get; set; }
+
+		public ComInteropInterfaceGenerator(TextWriter output) {
+			Output = output;
+		}
+		public void WriteLibrary(LibraryInfo lib) {
+			foreach (KeyValuePair<String, EnumInfo> enumi in lib.Enums) {
+				Output.WriteLine("{1} enum {0} {{", enumi.Key, TypeModifiers);
+				foreach (KeyValuePair<String, Int32> value in enumi.Value.Values) {
+					Output.WriteLine("{0} = {1},", value.Key, value.Value);
+				}
+				Output.WriteLine("}");
+			}
+			foreach (KeyValuePair<String, InterfaceInfo> intf in lib.Interfaces) {
+				if (IncludeComAttributes) {
+					if (ComInterfaceTypeIDispatch) {
+						Output.WriteLine("[InterfaceType(ComInterfaceType.InterfaceIsDual)]");
+					} else {
+						Output.WriteLine("[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]");
+					}
+					Output.WriteLine("[Guid(\"{0}\")]", intf.Value.IID);
+					Output.WriteLine("[ComImport()]");
+				}
+				Output.Write("{1} interface {0} ", intf.Key, TypeModifiers);
+				if (intf.Value.Extends != null) Output.Write(": {0} ", intf.Value.Extends.Name);
+				Output.WriteLine("{");
+				WriteInterfaceMembers(intf.Value);
+				Output.WriteLine("}");
+			}
+		}
+		public void WriteInterfaceMembers(InterfaceInfo intf) {
+			if (IncludeInheritedMembers && intf.Extends != null && intf.Extends.Name != "IUnknown") WriteInterfaceMembers(intf.Extends);
+			WriteInterfaceMembers(intf.Members);
+		}
+		public void WriteInterfaceMembers(ICollection<InterfaceMemberInfo> members) {
+			foreach (InterfaceMemberInfo member in members) {
+				if (member is PropertyInfo) {
+					PropertyInfo memberi = (PropertyInfo)member;
+					if (!memberi.Gettable && !memberi.Settable) continue;
+					Output.WriteLine("{0} {1} {{", memberi.Type.Name, memberi.Name);
+					if (memberi.Gettable) {
+						if (IncludeComAttributes) Output.Write("[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] ");
+						if (IncludeComAttributes) WriteTypeComMarshalAttributes(memberi.Type, "return");
+						Output.WriteLine("get;");
+					}
+					if (memberi.Settable) {
+						if (IncludeComAttributes) Output.Write("[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] ");
+						if (IncludeComAttributes) WriteTypeComMarshalAttributes(memberi.Type, "param");
+						Output.WriteLine("set;");
+					}
+					Output.WriteLine("}");
+				} else if (member is MethodInfo) {
+					MethodInfo memberi = (MethodInfo)member;
+					if (IncludeComAttributes) Output.Write("[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] ");
+					if (memberi.ReturnType == null) {
+						Output.Write("void ");
+					} else {
+						if (IncludeComAttributes) WriteTypeComMarshalAttributes(memberi.ReturnType, "return");
+						Output.Write("{0} ", memberi.ReturnType.Name);
+					}
+					Output.Write("{0}(", memberi.Name);
+					Boolean first = true;
+					foreach (MethodParameterInfo param in memberi.Parameters) {
+						if (first) {
+							first = false;
+						} else {
+							Output.Write(", ");
+						}
+						if (IncludeComAttributes) WriteTypeComMarshalAttributes(param.Type, null);
+						if (param.Output && !param.Input) Output.Write("out ");
+						else if (param.Reference) Output.Write("ref ");
+						Output.Write("{0} p{1}", param.Type.Name, param.Name);
+					}
+					Output.WriteLine(");");
+				}
+			}
+		}
+		public void WriteTypeComMarshalAttributes(TypeInfo type, String paramType) {
+			String MarshalAs = null;
+			if (type is InterfaceTypeInfo) {
+				MarshalAs = "Interface";
+			} else if (type is StringTypeInfo) {
+				MarshalAs = (type as StringTypeInfo).UnmanagedType.ToString();
+			}
+			if (MarshalAs != null) {
+				Output.Write("[");
+				if (paramType != null) Output.Write("{0}: ", paramType);
+				Output.Write("MarshalAs(UnmanagedType.{0})] ", MarshalAs);
+			}
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/InteropCodeGen/ComInteropProxyGenerator.cs	Fri May 06 04:02:43 2011 +0200
@@ -0,0 +1,274 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.IO;
+
+namespace VBoxSDK {
+	class ComInteropProxyGenerator {
+		public TextWriter Output { get; private set; }
+		public Boolean IncludeInheritedMembers { get; set; }
+		public String TypeModifiers { get; set; }
+
+		public ComInteropProxyGenerator(TextWriter output) {
+			Output = output;
+		}
+		public void WriteLibrary(LibraryInfo lib) {
+			Output.WriteLine("interface IComProxy {");
+			Output.WriteLine("IntPtr ComPointer { get; }");
+			Output.WriteLine("void AddRef();");
+			Output.WriteLine("}");
+			foreach (KeyValuePair<String, InterfaceInfo> intf in lib.Interfaces) {
+				WriteInterface(intf.Value);
+			}
+		}
+		public void WriteInterface(InterfaceInfo intf) {
+			/*List<InterfaceMemberInfo> members = new List<InterfaceMemberInfo>();
+			InterfaceInfo intfp = intf.Value;
+			while (intfp != null) {
+				members.AddRange(intfp.Members);
+				intfp = intfp.Extends;
+			}*/
+
+			foreach (InterfaceMemberInfo member in intf.Members) {
+				if (member is PropertyInfo) {
+					PropertyInfo memberi = (PropertyInfo)member;
+					if (memberi.Gettable) {
+						Output.Write("{2} delegate HRESULT {0}_{1}_get_Delegate(IntPtr pThis, ", intf.Name, memberi.Name, TypeModifiers);
+						if (memberi.Type is InterfaceTypeInfo) {
+							Output.WriteLine("out IntPtr value);");
+						} else {
+							WriteTypeComMarshalAttributes(memberi.Type, null);
+							Output.WriteLine("out {0} value);", memberi.Type.Name);
+						}
+					}
+					if (memberi.Settable) {
+						Output.Write("{2} delegate HRESULT {0}_{1}_set_Delegate(IntPtr pThis, ", intf.Name, memberi.Name, TypeModifiers);
+						if (memberi.Type is InterfaceTypeInfo) {
+							Output.WriteLine("IntPtr value);");
+						} else {
+							WriteTypeComMarshalAttributes(memberi.Type, null);
+							Output.WriteLine("{0} value);", memberi.Type.Name);
+						}
+					}
+				} else if (member is MethodInfo) {
+					MethodInfo memberi = (MethodInfo)member;
+					Output.Write("{0} delegate ", TypeModifiers);
+					Output.Write("HRESULT ");
+					Output.Write("{0}_{1}_Delegate(IntPtr mThis", intf.Name, memberi.Name);
+					foreach (MethodParameterInfo param in memberi.Parameters) {
+						Output.Write(", ");
+						if (param.Type is InterfaceTypeInfo) {
+							if (param.Output && !param.Input) Output.Write("out ");
+							else if (param.Reference) Output.Write("ref ");
+							Output.Write("IntPtr p{0}", param.Name);
+						} else {
+							WriteTypeComMarshalAttributes(param.Type, null);
+							if (param.Output && !param.Input) Output.Write("out ");
+							else if (param.Reference) Output.Write("ref ");
+							Output.Write("{0} p{1}", param.Type.Name, param.Name);
+						}
+					}
+					if (memberi.ReturnType != null) {
+						Output.Write(", ");
+						if (memberi.ReturnType is InterfaceTypeInfo) {
+							Output.Write("out IntPtr mOut");
+						} else {
+							WriteTypeComMarshalAttributes(memberi.ReturnType, null);
+							Output.Write("out {0} mOut", memberi.ReturnType.Name);
+						}
+					}
+					Output.WriteLine(");");
+				}
+			}
+
+			Output.WriteLine("{1} struct {0}_vtable {{", intf.Name, TypeModifiers);
+			if (intf.Extends != null) {
+				Output.WriteLine("public {0}_vtable {0};", intf.Extends.Name);
+			}
+			foreach (InterfaceMemberInfo member in intf.Members) {
+				if (member is PropertyInfo) {
+					PropertyInfo memberi = (PropertyInfo)member;
+					if (memberi.Gettable) {
+						Output.WriteLine("[MarshalAs(UnmanagedType.FunctionPtr)] public {0}_{1}_get_Delegate get_{1};", intf.Name, memberi.Name);
+					}
+					if (memberi.Settable) {
+						Output.WriteLine("[MarshalAs(UnmanagedType.FunctionPtr)] public {0}_{1}_set_Delegate set_{1};", intf.Name, memberi.Name);
+					}
+				} else if (member is MethodInfo) {
+					MethodInfo memberi = (MethodInfo)member;
+					Output.WriteLine("[MarshalAs(UnmanagedType.FunctionPtr)] public {0}_{1}_Delegate {1};", intf.Name, memberi.Name);
+				}
+			}
+			Output.WriteLine("}");
+
+			Output.WriteLine("{1} unsafe class {0}_Proxy : IComProxy, {0} {{", intf.Name, TypeModifiers);
+			Output.WriteLine("public static Guid IID = new Guid(\"{0}\");", intf.IID);
+			Output.WriteLine("private IntPtr pointer;");
+			Output.WriteLine("private {0}_vtable functions;", intf.Name);
+			Output.WriteLine("public {0}_Proxy(IntPtr p) {{", intf.Name);
+			Output.WriteLine("IUnknown_vtable ft = (IUnknown_vtable)Marshal.PtrToStructure(*(IntPtr*)p, typeof(IUnknown_vtable));");
+			Output.WriteLine("Guid IIDCopy = IID;");
+			Output.WriteLine("HRESULT hr = ft.QueryInterface(p, ref IIDCopy, out pointer);");
+			Output.WriteLine("Marshal.ThrowExceptionForHR(hr);");
+			//Output.WriteLine("ft.AddRef(p);");
+			Output.WriteLine("functions = ({0}_vtable)Marshal.PtrToStructure(*(IntPtr*)pointer, typeof({0}_vtable));", intf.Name);
+			Output.WriteLine("}");
+			Output.WriteLine("IntPtr IComProxy.ComPointer { get { return pointer; } }");
+			Output.Write("~{0}_Proxy() {{ functions", intf.Name);
+			{
+				InterfaceInfo intfp = intf;
+				while (intfp.Extends != null && intfp.Name != "IUnknown") {
+					intfp = intfp.Extends;
+					Output.Write(".{0}", intfp.Name);
+				}
+			}
+			Output.WriteLine(".Release(pointer); }");
+			WriteInterfaceMembers(intf, "");
+			Output.WriteLine("}");
+		}
+		private void WriteInterfaceMembers(InterfaceInfo intf, String ftprefix) {
+			if (intf.Extends != null) WriteInterfaceMembers(intf.Extends, ftprefix + "." + intf.Extends.Name);
+			WriteInterfaceMembers(intf.Members, ftprefix);
+		}
+		private void WriteInterfaceMembers(ICollection<InterfaceMemberInfo> members, String ftprefix) {
+			foreach (InterfaceMemberInfo member in members) {
+				if (member is PropertyInfo) {
+					PropertyInfo memberi = (PropertyInfo)member;
+					if (!memberi.Gettable && !memberi.Settable) continue;
+					Output.WriteLine("public {0} {1} {{", memberi.Type.Name, memberi.Name);
+					if (memberi.Gettable) {
+						Output.WriteLine("get {");
+						if (memberi.Type is InterfaceTypeInfo) {
+							Output.WriteLine("IntPtr value;");
+						} else {
+							Output.WriteLine("{0} value;", memberi.Type.Name);
+						}
+						Output.WriteLine("HRESULT hr = functions{1}.get_{0}(pointer, out value);", memberi.Name, ftprefix);
+						Output.WriteLine("Marshal.ThrowExceptionForHR(hr);");
+						if (memberi.Type is InterfaceTypeInfo) {
+							Output.WriteLine("return value == IntPtr.Zero ? null : new {0}_Proxy(value);", memberi.Type.Name);
+						} else {
+							Output.WriteLine("return value;");
+						}
+						Output.WriteLine("}");
+					}
+					if (memberi.Settable) {
+						Output.WriteLine("set {");
+						if (memberi.Type is InterfaceTypeInfo) {
+							Output.WriteLine("IntPtr pvalue;");
+							Output.WriteLine("if (pvalue == null) {");
+							Output.WriteLine("pvalue = IntPtr.Zero;");
+							Output.WriteLine("} else if (pvalue is IComProxy) {");
+							Output.WriteLine("((IComProxy)value).AddRef();");
+							Output.WriteLine("pvalue = ((IComProxy)value).ComPointer;");
+							Output.WriteLine("} else {");
+							Output.WriteLine("pvalue = Marshal.GetIUnknownForObject(value);");
+							Output.WriteLine("}");
+							Output.WriteLine("HRESULT hr = functions{1}.set_{0}(pointer, pvalue);", memberi.Name, ftprefix);
+						} else {
+							Output.WriteLine("HRESULT hr = functions{1}.set_{0}(pointer, value);", memberi.Name, ftprefix);
+						}
+						Output.WriteLine("Marshal.ThrowExceptionForHR(hr);");
+						Output.WriteLine("}");
+					}
+					Output.WriteLine("}");
+				} else if (member is MethodInfo) {
+					MethodInfo memberi = (MethodInfo)member;
+					Output.Write("public ");
+					if (memberi.ReturnType == null) {
+						Output.Write("void");
+					} else {
+						Output.Write(memberi.ReturnType.Name);
+					}
+					Output.Write(" {0}(", memberi.Name);
+					Boolean first = true;
+					foreach (MethodParameterInfo parameter in memberi.Parameters) {
+						if (first) {
+							first = false;
+						} else {
+							Output.Write(", ");
+						}
+						if (parameter.Output && !parameter.Input) {
+							Output.Write("out ");
+						} else if (parameter.Reference) {
+							Output.Write("ref ");
+						}
+						Output.Write("{0} p{1}", parameter.Type.Name, parameter.Name);
+					}
+					Output.WriteLine(") {");
+					if (memberi.ReturnType != null) {
+						if (memberi.ReturnType is InterfaceTypeInfo) {
+							Output.WriteLine("IntPtr retval;");
+						} else {
+							Output.WriteLine("{0} retval;", memberi.ReturnType.Name);
+						}
+					}
+					foreach (MethodParameterInfo parameter in memberi.Parameters) {
+						if (parameter.Type is InterfaceTypeInfo) {
+							Output.WriteLine("IntPtr lp{0};", parameter.Name);
+							if (parameter.Input) {
+								Output.WriteLine("if (p{0} == null) {{", parameter.Name);
+								Output.WriteLine("lp{0} = IntPtr.Zero;", parameter.Name);
+								Output.WriteLine("}} else if (p{0} is IComProxy) {{", parameter.Name);
+								Output.WriteLine("((IComProxy)p{0}).AddRef();", parameter.Name);
+								Output.WriteLine("lp{0} = ((IComProxy)p{0}).ComPointer;", parameter.Name);
+								Output.WriteLine("} else {");
+								Output.WriteLine("lp{0} = Marshal.GetIUnknownForObject(p{0});", parameter.Name);
+								Output.WriteLine("}");
+							}
+						}
+					}
+
+					Output.Write("HRESULT hr = functions{1}.{0}(pointer", memberi.Name, ftprefix);
+					foreach (MethodParameterInfo parameter in memberi.Parameters) {
+						Output.Write(", ");
+						if (parameter.Output && !parameter.Input) {
+							Output.Write("out ");
+						} else if (parameter.Reference) {
+							Output.Write("ref ");
+						}
+						if (parameter.Type is InterfaceTypeInfo) {
+							Output.Write("lp{0}", parameter.Name);
+						} else {
+							Output.Write("p{0}", parameter.Name);
+						}
+					}
+					if (memberi.ReturnType != null) Output.Write(", out retval");
+					Output.WriteLine(");");
+					Output.WriteLine("Marshal.ThrowExceptionForHR(hr);");
+
+					foreach (MethodParameterInfo parameter in memberi.Parameters) {
+						if (parameter.Type is InterfaceTypeInfo) {
+							if (parameter.Output) {
+								Output.WriteLine("p{0} = lp{0} == IntPtr.Zero ? null : new {1}_Proxy(lp{0});", parameter.Name, parameter.Type.Name);
+							}
+						}
+					}
+
+					if (memberi.ReturnType != null) {
+						if (memberi.ReturnType is InterfaceTypeInfo) {
+							Output.WriteLine("return retval == IntPtr.Zero ? null : new {0}_Proxy(retval);", memberi.ReturnType.Name);
+						} else {
+							Output.WriteLine("return retval;");
+						}
+					}
+					Output.WriteLine("}");
+				}
+			}
+		}
+		public void WriteTypeComMarshalAttributes(TypeInfo type, String paramType) {
+			if (type == null) return;
+			String MarshalAs = null;
+			if (type is InterfaceTypeInfo) {
+				MarshalAs = "Interface";
+			} else if (type is StringTypeInfo) {
+				MarshalAs = (type as StringTypeInfo).UnmanagedType.ToString();
+			}
+			if (MarshalAs != null) {
+				Output.Write("[");
+				if (paramType != null) Output.Write("{0}: ", paramType);
+				Output.Write("MarshalAs(UnmanagedType.{0})] ", MarshalAs);
+			}
+		}
+	}
+}
--- a/InteropCodeGen/InteropCodeGen.csproj	Fri May 06 03:56:30 2011 +0200
+++ b/InteropCodeGen/InteropCodeGen.csproj	Fri May 06 04:02:43 2011 +0200
@@ -35,7 +35,12 @@
     <Reference Include="System.Xml" />
   </ItemGroup>
   <ItemGroup>
-    <Compile Include="gendotnet.cs" />
+    <Compile Include="ComInteropInterfaceGenerator.cs" />
+    <Compile Include="ComInteropProxyGenerator.cs" />
+    <Compile Include="LibraryInformation.cs" />
+    <Compile Include="Program.cs" />
+    <Compile Include="XidlParser.cs" />
+    <None Include="gendotnet.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
   </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/InteropCodeGen/LibraryInformation.cs	Fri May 06 04:02:43 2011 +0200
@@ -0,0 +1,100 @@
+using System;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+
+namespace VBoxSDK {
+	public class LibraryInfo {
+		public Dictionary<String, EnumInfo> Enums { get; private set; }
+		public Dictionary<String, InterfaceInfo> Interfaces { get; private set; }
+		public LibraryInfo() {
+			Enums = new Dictionary<string, EnumInfo>();
+			Interfaces = new Dictionary<string, InterfaceInfo>();
+		}
+	}
+	public class EnumInfo {
+		public Dictionary<String, Int32> Values { get; private set; }
+		public String Name { get; private set; }
+		public EnumInfo(String name) {
+			Name = name;
+			Values = new Dictionary<string, int>();
+		}
+	}
+	public class InterfaceInfo {
+		public InterfaceInfo Extends { get; private set; }
+		public Guid IID { get; private set; }
+		public String Name { get; private set; }
+		public List<InterfaceMemberInfo> Members { get; private set; }
+		public InterfaceInfo(String name, Guid iid) : this(name, iid, null) { }
+		public InterfaceInfo(String name, Guid iid, InterfaceInfo extends) {
+			Name = name;
+			IID = iid;
+			Extends = extends;
+			Members = new List<InterfaceMemberInfo>();
+		}
+	}
+	public class InterfaceMemberInfo {
+	}
+	public class PropertyInfo : InterfaceMemberInfo {
+		public String Name { get; private set; }
+		public TypeInfo Type { get; private set; }
+		public Boolean Gettable { get; private set; }
+		public Boolean Settable { get; private set; }
+		public PropertyInfo(String name, TypeInfo type, Boolean gettable, Boolean settable) {
+			Name = name;
+			Type = type;
+			Gettable = gettable;
+			Settable = settable;
+		}
+	}
+	public class MethodInfo : InterfaceMemberInfo {
+		public String Name { get; private set; }
+		public TypeInfo ReturnType { get; private set; }
+		public List<MethodParameterInfo> Parameters { get; private set; }
+		public MethodInfo(String name, TypeInfo returnType) {
+			Name = name;
+			ReturnType = returnType;
+			Parameters = new List<MethodParameterInfo>();
+		}
+	}
+	public class MethodParameterInfo {
+		public String Name { get; private set; }
+		public TypeInfo Type { get; private set; }
+		public Boolean Input { get; private set; }
+		public Boolean Reference { get; private set; }
+		public Boolean Output { get; private set; }
+		public MethodParameterInfo(String name, TypeInfo type, Boolean input, Boolean reference, Boolean output) {
+			Name = name;
+			Type = type;
+			Input = input;
+			Reference = reference | output;
+			Output = output;
+		}
+	}
+	public class TypeInfo {
+		public String Name { get; private set; }
+		public TypeInfo(String name) {
+			Name = name;
+		}
+	}
+	public class ValueTypeInfo : TypeInfo {
+		public ValueTypeInfo(String name)
+			: base(name) {
+		}
+		public ValueTypeInfo(Type type)
+			: base(type.Name) {
+		}
+	}
+	public class StringTypeInfo : TypeInfo {
+		public UnmanagedType UnmanagedType { get; set; }
+		public StringTypeInfo(UnmanagedType unmanagedType) : base("String") {
+			UnmanagedType = unmanagedType;
+		}
+		public StringTypeInfo()
+			: this(UnmanagedType.BStr) {
+		}
+	}
+	public class InterfaceTypeInfo : TypeInfo {
+		public InterfaceTypeInfo(String name) : base(name) {
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/InteropCodeGen/Program.cs	Fri May 06 04:02:43 2011 +0200
@@ -0,0 +1,115 @@
+using System;
+using System.Xml.XPath;
+using System.Collections.Generic;
+using System.IO;
+using System.Runtime.InteropServices;
+
+namespace VBoxSDK {
+	class Program {
+		public static void Main(String[] args) {
+			Boolean TargetIsMono = false;
+
+			XidlParser parser = new XidlParser();
+			XPathDocument xidlDoc = new XPathDocument("VirtualBox.xidl");
+			if (TargetIsMono) {
+				parser.Types["wstring"] = new StringTypeInfo(UnmanagedType.LPWStr);
+				parser.BaseInterfaceType = parser.Library.Interfaces["IUnknown"];
+			} else {
+				parser.Types["wstring"] = new StringTypeInfo(UnmanagedType.BStr);
+				parser.BaseInterfaceType = parser.Library.Interfaces["IDispatch"];
+			}
+			parser.Parse(xidlDoc.CreateNavigator());
+			foreach (InterfaceInfo intf in parser.Library.Interfaces.Values) {
+				GnomeSort(intf.Members,	delegate(InterfaceMemberInfo a, InterfaceMemberInfo b) {
+					if (b is PropertyInfo && a is MethodInfo) return 1;
+					else if (a is PropertyInfo && b is MethodInfo) return -1;
+					return 0;
+				});
+			}
+			using (TextWriter outfile = File.CreateText("Interfaces.txt")) {
+				PrintTypeTree(outfile, parser.Library);
+			}
+			using (TextWriter outfile = File.CreateText("Interfaces.cs")) {
+				outfile.WriteLine("using System;");
+				outfile.WriteLine("using System.Runtime.InteropServices;");
+				outfile.WriteLine("using System.Runtime.CompilerServices;");
+				outfile.WriteLine("namespace VirtualBox {");
+				ComInteropInterfaceGenerator igen = new ComInteropInterfaceGenerator(outfile);
+				igen.IncludeInheritedMembers = true;
+				igen.IncludeComAttributes = true;
+				igen.ComInterfaceTypeIDispatch = !TargetIsMono;
+				igen.TypeModifiers = "public";
+				igen.WriteLibrary(parser.Library);
+				outfile.WriteLine("}");
+			}
+			parser.Library.Interfaces["IUnknown"].Members.Add(new MethodInfo("QueryInterface", new ValueTypeInfo("IntPtr")));
+			(parser.Library.Interfaces["IUnknown"].Members[0] as MethodInfo).Parameters.Add(new MethodParameterInfo("riid", new ValueTypeInfo("Guid"), true, true, false));
+			parser.Library.Interfaces["IUnknown"].Members.Add(new MethodInfo("AddRef", null));
+			parser.Library.Interfaces["IUnknown"].Members.Add(new MethodInfo("Release", null));
+			parser.Library.Interfaces["IDispatch"].Members.Add(new MethodInfo("GetTypeInfoCount", null));
+			parser.Library.Interfaces["IDispatch"].Members.Add(new MethodInfo("GetTypeInfo", null));
+			parser.Library.Interfaces["IDispatch"].Members.Add(new MethodInfo("GetIDsOfNames", null));
+			parser.Library.Interfaces["IDispatch"].Members.Add(new MethodInfo("Invoke", null));
+			parser.Library.Interfaces["IErrorInfo"].Members.Add(new MethodInfo("dummy1", null));
+			parser.Library.Interfaces["IErrorInfo"].Members.Add(new MethodInfo("dummy2", null));
+			parser.Library.Interfaces["IErrorInfo"].Members.Add(new MethodInfo("dummy3", null));
+			parser.Library.Interfaces["IErrorInfo"].Members.Add(new MethodInfo("dummy4", null));
+			parser.Library.Interfaces["IErrorInfo"].Members.Add(new MethodInfo("dummy5", null));
+			if (TargetIsMono) {
+				parser.Library.Interfaces["IErrorInfo"].Members.Add(new MethodInfo("dummy6", null));
+				parser.Library.Interfaces["IErrorInfo"].Members.Add(new MethodInfo("dummy7", null));
+				parser.Library.Interfaces["IErrorInfo"].Members.Add(new MethodInfo("dummy8", null));
+				parser.Library.Interfaces["IErrorInfo"].Members.Add(new MethodInfo("dummy9", null));
+				parser.Library.Interfaces["IErrorInfo"].Members.Add(new MethodInfo("dummy10", null));
+			}
+			using (TextWriter outfile = File.CreateText("Proxy.cs")) {
+				outfile.WriteLine("using System;");
+				outfile.WriteLine("using System.Runtime.InteropServices;");
+				outfile.WriteLine("using HRESULT = System.Int32;");
+				outfile.WriteLine("namespace VirtualBox {");
+				ComInteropProxyGenerator igen = new ComInteropProxyGenerator(outfile);
+				igen.IncludeInheritedMembers = true;
+				igen.TypeModifiers = "public";
+				igen.WriteLibrary(parser.Library);
+				outfile.WriteLine("}");
+			}
+			Console.WriteLine("Done.");
+			Console.ReadLine();
+		}
+		private static void GnomeSort<T>(IList<T> a, Comparison<T> comparer) {
+			int pos = 1;
+			while (pos < a.Count) {
+				if (comparer(a[pos], a[pos - 1]) >= 0) {
+					pos++;
+				} else {
+					T tmp = a[pos];
+					a[pos] = a[pos - 1];
+					a[pos - 1] = tmp;
+					if (pos > 1) pos--; else pos++;
+				}
+			}
+		}
+		private static void PrintTypeTree(TextWriter output, LibraryInfo lib) {
+			foreach (KeyValuePair<String, EnumInfo> enumi in lib.Enums) {
+				output.WriteLine("enum {0};", enumi.Key);
+			}
+			foreach (KeyValuePair<String, InterfaceInfo> intf in lib.Interfaces) {
+				output.Write("interface {0}({1}) ", intf.Key, intf.Value.IID);
+				if (intf.Value.Extends != null) output.Write(": {0} ", intf.Value.Extends.Name);
+				output.WriteLine("{");
+				foreach (InterfaceMemberInfo member in intf.Value.Members) {
+					if (member is PropertyInfo) {
+						PropertyInfo memberi = (PropertyInfo)member;
+						output.WriteLine("property {0};", memberi.Name);
+					} else if (member is MethodInfo) {
+						MethodInfo memberi = (MethodInfo)member;
+						output.WriteLine("method {0};", memberi.Name);
+					} else {
+						output.WriteLine("unknown member;");
+					}
+				}
+				output.WriteLine("}");
+			}
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/InteropCodeGen/XidlParser.cs	Fri May 06 04:02:43 2011 +0200
@@ -0,0 +1,208 @@
+using System;
+using System.Xml.XPath;
+using System.IO;
+using System.Collections.Generic;
+
+namespace VBoxSDK {
+	public class XidlParser {
+		public LibraryInfo Library { get; private set; }
+		public TypeInfo UnknownType { get; set; }
+		public InterfaceInfo BaseInterfaceType { get; set; }
+		public InterfaceInfo ErrorInterfaceType { get; set; }
+		enum ParameterType {
+			In,
+			Out,
+			Reference,
+			Return,
+			Param,
+		}
+		public Dictionary<String, TypeInfo> Types = new Dictionary<string, TypeInfo>();
+
+		void AddInterfaceTypes(params String[] names) {
+			foreach (String name in names) Types.Add(name, new InterfaceTypeInfo(name));
+		}
+		void AddEnumTypes(params String[] names) {
+			foreach (String name in names) Types.Add(name, new ValueTypeInfo(name));
+		}
+		void InitTypes() {
+			Types.Add("short", new ValueTypeInfo(typeof(Int32)));
+			Types.Add("unsigned short", new ValueTypeInfo(typeof(UInt16)));
+			Types.Add("unsigned long", new ValueTypeInfo(typeof(UInt32)));
+			Types.Add("long long", new ValueTypeInfo(typeof(Int64)));
+			Types.Add("long", new ValueTypeInfo(typeof(Int32)));
+			Types.Add("octet", new ValueTypeInfo(typeof(Byte)));
+			Types.Add("unsigned long long", new ValueTypeInfo(typeof(UInt32)));
+			//Types.Add("boolean", new TypeInfo("Boolean", "MarshalAs(UnmanagedType.Bool)"));
+			Types.Add("boolean", new ValueTypeInfo(typeof(Int32)));
+			//Types.Add("wstring", new ValueTypeInfo("String", "MarshalAs(UnmanagedType.LPWStr)"));
+			//Types.Add("uuid", new TypeInfo("Guid", true, "MarshalAs(UnmanagedType.LPStruct)"));
+			//Types.Add("uuid", new ValueTypeInfo("Guid", "MarshalAs(UnmanagedType.LPStruct)"));
+			Types.Add("wstring", new StringTypeInfo());
+
+			Types.Add("$unknown", new ValueTypeInfo(typeof(IntPtr)));
+			AddInterfaceTypes("IMachine", "ISession", "IVirtualBox", "IHost", "IConsole", "ISystemProperties");
+			AddInterfaceTypes("IProgress", "IDisplay", "IMouse", "IKeyboard", "IFramebuffer", "IFramebufferOverlay");
+			AddInterfaceTypes("IMachineDebugger", "IVirtualBoxErrorInfo", "IEventSource", "IEventListener", "IEventContext");
+			AddInterfaceTypes("IConsoleCallback", "IEvent", "IBandwidthControl", "IVRDEServerInfo", "IAdditionsFacility");
+			AddInterfaceTypes("IExtPackPlugIn", "IExtPackFile", "IExtPack", "IBIOSSettings", "IVFSExplorer", "IUSBController");
+			AddInterfaceTypes("IStorageController", "IVRDPServer", "ISnapshot", "INATEngine", "IUSBDeviceFilter");
+			AddInterfaceTypes("IMediumAttachment", "IUSBDevice", "IParallelPort", "ISerialPort", "INetworkAdapter");
+			AddInterfaceTypes("IMedium", "IGuestOSType", "ISharedFolder", "IPerformanceCollector", "IDHCPServer");
+			AddInterfaceTypes("IAppliance", "IVirtualBoxCallback", "IPerformanceMetric", "IMediumFormat", "IHostUSBDevice");
+			AddInterfaceTypes("IHostNetworkInterface", "IHostUSBDeviceFilter", "IRemoteDisplayInfo", "IGuest");
+			AddInterfaceTypes("IVirtualSystemDescription", "IAudioAdapter", "IExtPackManager", "IVRDEServer");
+			AddInterfaceTypes("IPciDeviceAttachment", "IBandwidthGroup");
+
+			AddEnumTypes("LockType", "MediumVariant", "AccessMode", "NATProtocol", "FirmwareType", "StorageControllerType");
+			AddEnumTypes("StorageBus", "SessionType", "SessionState", "USBDeviceState", "USBDeviceFilterAction", "Scope");
+			AddEnumTypes("AudioControllerType", "AudioDriverType", "VRDPAuthType", "MachineState", "NetworkAdapterType");
+			AddEnumTypes("NetworkAttachmentType", "PortMode", "DeviceType", "MediumState", "VFSType", "MediumType");
+			AddEnumTypes("HostNetworkInterfaceType", "DeviceActivity", "HostNetworkInterfaceMediumType", "HostNetworkInterfaceStatus");
+			AddEnumTypes("ProcessorFeature", "BIOSBootMenuMode", "VirtualSystemDescriptionType", "VirtualSystemDescriptionValueType");
+			AddEnumTypes("KeyboardHidType", "ClipboardMode", "PointingHidType", "CPUPropertyType", "HWVirtExPropertyType");
+			AddEnumTypes("ChipsetType", "FaultToleranceState", "BandwidthGroupType", "ExecuteProcessStatus", "VBoxEventType");
+			AddEnumTypes("GuestMonitorChangedEventType", "AuthType", "NetworkAdapterPromiscModePolicy", "AdditionsRunLevelType");
+			AddEnumTypes("AdditionsFacilityStatus", "AdditionsFacilityType", "AdditionsFacilityClass", "CleanupMode", "DataType");
+		}
+
+		public XidlParser() {
+			Library = new LibraryInfo();
+			UnknownType = new ValueTypeInfo("IntPtr");
+			Library.Interfaces.Add("IUnknown", new InterfaceInfo("IUnknown", new Guid("00000000-0000-0000-C000-000000000046")));
+			Library.Interfaces.Add("IErrorInfo", new InterfaceInfo("IErrorInfo", new Guid("00000000-0000-0000-C000-000000000046"), Library.Interfaces["IUnknown"]));
+			Library.Interfaces.Add("IDispatch", new InterfaceInfo("IDispatch", new Guid("00020400-0000-0000-C000-000000000046"), Library.Interfaces["IUnknown"]));
+			BaseInterfaceType = Library.Interfaces["IUnknown"];
+			ErrorInterfaceType = Library.Interfaces["IErrorInfo"];
+			InitTypes();
+		}
+
+		public void Parse(XPathNavigator nav) {
+			//XPathDocument doc = new XPathDocument("VirtualBox.xidl");
+			//XPathNavigator nav = doc.CreateNavigator();
+			nav = nav.SelectSingleNode("/idl/library"); //[@name='VirtualBox']
+			foreach (XPathNavigator intf in nav.Select("interface")) {
+				ProcessInterface(intf, nav);
+			}
+			foreach (XPathNavigator intf in nav.Select("enum")) {
+				ProcessEnum(intf);
+			}
+		}
+		void ProcessEnum(XPathNavigator nav) {
+			String typeName = nav.SelectSingleNode("@name").Value;
+			EnumInfo typeInfo = new EnumInfo(typeName);
+			foreach (XPathNavigator member in nav.SelectChildren(XPathNodeType.Element)) {
+				switch (member.Name) {
+					case "desc": break;
+					case "const": {
+							String numberString = member.SelectSingleNode("@value").Value;
+							Int32 number = 0;
+							if (numberString.StartsWith("0x", StringComparison.InvariantCultureIgnoreCase)) {
+								number = Int32.Parse(numberString.Substring(2), System.Globalization.NumberStyles.HexNumber);
+							} else {
+								number = Int32.Parse(numberString);
+							}
+							typeInfo.Values.Add(member.SelectSingleNode("@name").Value, number);
+						} break;
+					default:
+						Console.Error.WriteLine("Unknown member type {0}", member.Name);
+						break;
+				}
+			}
+			Library.Enums.Add(typeName, typeInfo);
+		}
+		void ProcessInterface(XPathNavigator nav, XPathNavigator parentNav) {
+			String typeName = nav.SelectSingleNode("@name").Value;
+			String typeIid = nav.SelectSingleNode("@uuid").Value;
+			XPathItem item = nav.SelectSingleNode("@extends");
+			InterfaceInfo typeExtends = null;
+			if (item != null) {
+				switch (item.Value) {
+					case "$unknown": typeExtends = BaseInterfaceType; break;
+					case "$errorinfo": typeExtends = ErrorInterfaceType; break;
+					default: typeExtends = Library.Interfaces[item.Value]; break;
+				}
+			}
+			InterfaceInfo typeInfo = new InterfaceInfo(typeName, new Guid(typeIid), typeExtends);
+			foreach (XPathNavigator member in nav.SelectChildren(XPathNodeType.Element)) {
+				switch (member.Name) {
+					case "desc": break;
+					case "attribute": {
+							String mName = member.SelectSingleNode("@name").Value;
+							item = member.SelectSingleNode("@readonly");
+							Boolean mReadOnly = item == null ? false : item.Value == "yes";
+							item = member.SelectSingleNode("@writeonly");
+							Boolean mWriteOnly = item == null ? false : item.Value == "yes";
+							mName = mName.Substring(0, 1).ToUpper() + mName.Substring(1);
+							PropertyInfo mInfo = new PropertyInfo(mName, GetTypeDeclaration(member), !mWriteOnly, !mReadOnly);
+							typeInfo.Members.Add(mInfo);
+						} break;
+					case "method": {
+							String mName = member.SelectSingleNode("@name").Value;
+							XPathNodeIterator mParamReturn = member.Select("param[@dir='return']");
+							bool mReturn = false;
+							TypeInfo mReturnType = null;
+							if (mParamReturn == null || mParamReturn.Count != 1) {
+							} else {
+								mParamReturn.MoveNext();
+								mReturn = true;
+								mReturnType = GetTypeDeclaration(mParamReturn.Current);
+							}
+							mName = mName.Substring(0, 1).ToUpper() + mName.Substring(1);
+							MethodInfo mInfo = new MethodInfo(mName, mReturnType);
+							foreach (XPathNavigator mParam in member.Select("param")) {
+								String pDir = mParam.SelectSingleNode("@dir").Value;
+								if (pDir == "return" && mReturn) continue;
+								ParameterType pt = pDir == "out" ? ParameterType.Out : ParameterType.In;
+								TypeInfo mType = GetTypeDeclaration(mParam, ref pt);
+								mInfo.Parameters.Add(new MethodParameterInfo(mParam.SelectSingleNode("@name").Value, mType, pDir != "out", pt == ParameterType.Reference, pDir == "out"));
+							}
+							typeInfo.Members.Add(mInfo);
+						} break;
+					default:
+						Console.Error.WriteLine("Unknown member type {0}", member.Name);
+						break;
+				}
+			}
+			Library.Interfaces.Add(typeName, typeInfo);
+		}
+		private TypeInfo GetTypeDeclaration(XPathNavigator nav) {
+			ParameterType paramType = ParameterType.Param;
+			return GetTypeDeclaration(nav, ref paramType);
+		}
+		private TypeInfo GetTypeDeclaration(XPathNavigator nav, ref ParameterType paramType) {
+			String mType = nav.SelectSingleNode("@type").Value;
+			XPathItem item;
+			item = nav.SelectSingleNode("@mod");
+			String mMod = item == null ? null : item.Value;
+			item = nav.SelectSingleNode("@safearray");
+			Boolean pArray = item == null ? false : item.Value == "yes";
+
+			TypeInfo t;
+			if (!Types.TryGetValue(mType, out t)) {
+				t = null;
+			}
+			if (mMod == "ptr") {
+				if (paramType == ParameterType.In) {
+					paramType = ParameterType.Reference;
+				} else {
+					t = new ValueTypeInfo(typeof(IntPtr));
+				}
+			} else if (mMod == "string") {
+				t = Types["wstring"];
+			} else if (mMod != null) {
+				Console.Error.WriteLine("Type modifier {0} is not supported", mMod);
+				t = UnknownType;
+			}
+			if (t == null) {
+				Console.Error.WriteLine("Type {0} is not supported", mType);
+				t = UnknownType;
+			}
+			if (pArray) {
+				Console.Error.WriteLine("Array type not supported");
+				t = null;
+				t = UnknownType;
+			}
+			return t;
+		}
+	}
+}
\ No newline at end of file