# HG changeset patch # User Ivo Smits # Date 1304647363 -7200 # Node ID e640ca67b819831e6ca0be99f84f5372c0d9c4a8 # Parent 00fb4879d2739060a475add8ce9a4344e962e141 Added extended COM interop code generator for interfaces and proxies diff -r 00fb4879d273 -r e640ca67b819 InteropCodeGen/ComInteropInterfaceGenerator.cs --- /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 enumi in lib.Enums) { + Output.WriteLine("{1} enum {0} {{", enumi.Key, TypeModifiers); + foreach (KeyValuePair value in enumi.Value.Values) { + Output.WriteLine("{0} = {1},", value.Key, value.Value); + } + Output.WriteLine("}"); + } + foreach (KeyValuePair 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 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); + } + } + } +} diff -r 00fb4879d273 -r e640ca67b819 InteropCodeGen/ComInteropProxyGenerator.cs --- /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 intf in lib.Interfaces) { + WriteInterface(intf.Value); + } + } + public void WriteInterface(InterfaceInfo intf) { + /*List members = new List(); + 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 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); + } + } + } +} diff -r 00fb4879d273 -r e640ca67b819 InteropCodeGen/InteropCodeGen.csproj --- 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 @@ - + + + + + + diff -r 00fb4879d273 -r e640ca67b819 InteropCodeGen/LibraryInformation.cs --- /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 Enums { get; private set; } + public Dictionary Interfaces { get; private set; } + public LibraryInfo() { + Enums = new Dictionary(); + Interfaces = new Dictionary(); + } + } + public class EnumInfo { + public Dictionary Values { get; private set; } + public String Name { get; private set; } + public EnumInfo(String name) { + Name = name; + Values = new Dictionary(); + } + } + public class InterfaceInfo { + public InterfaceInfo Extends { get; private set; } + public Guid IID { get; private set; } + public String Name { get; private set; } + public List 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(); + } + } + 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 Parameters { get; private set; } + public MethodInfo(String name, TypeInfo returnType) { + Name = name; + ReturnType = returnType; + Parameters = new List(); + } + } + 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) { + } + } +} diff -r 00fb4879d273 -r e640ca67b819 InteropCodeGen/Program.cs --- /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(IList a, Comparison 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 enumi in lib.Enums) { + output.WriteLine("enum {0};", enumi.Key); + } + foreach (KeyValuePair 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("}"); + } + } + } +} diff -r 00fb4879d273 -r e640ca67b819 InteropCodeGen/XidlParser.cs --- /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 Types = new Dictionary(); + + 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