view 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 source

???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);
			}
		}
	}
}