diff InteropCodeGen/ComInteropProxyGenerator.cs @ 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
children a7650e26195f
line wrap: on
line diff
--- /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);
+			}
+		}
+	}
+}