view InteropCodeGen/gendotnet.cs @ 2:f1deea9c97a0

Cleaned up the interop code generator, added wrapper application to initialize kernel driver and run mono
author Ivo Smits
date Wed, 04 May 2011 16:10:08 +0200
parents e1ec7bf71313
children 64226294e26b
line wrap: on
line source
//+reference System.dll
//+reference System.Xml.dll
using System;
using System.Xml.XPath;
using System.IO;
using System.Collections.Generic;
class Program {
	enum ParameterType {
		In,
		Out,
		Reference,
		Return,
		Param,
	}
	class TypeInfo {
		public String Name { get; private set; }
		public String[] Attributes { get; private set; }

		public TypeInfo(String name, params String[] attributes) {
			this.Name = name;
			this.Attributes = attributes;
		}
		public void WriteDeclaration(TextWriter o, ParameterType vartype) {
			WriteAttributes(o, vartype);
			o.Write(Name);
		}
		public void WriteAttributes(TextWriter o, ParameterType vartype) {
			foreach (String attribute in Attributes) {
				o.Write("[");
				if (vartype == ParameterType.Return) o.Write("return: ");
				else if (vartype == ParameterType.Param) o.Write("param: ");
				o.Write(attribute);
				o.Write("] ");
			}
			if (vartype == ParameterType.Out) o.Write("out ");
			else if (vartype == ParameterType.Reference) o.Write("ref ");
		}
	}
	static Dictionary<String, TypeInfo> Types = new Dictionary<string, TypeInfo>();
	static void AddInterfaceTypes(params String[] names) {
		foreach (String name in names) Types.Add(name, new TypeInfo(name, "MarshalAs(UnmanagedType.Interface)"));
	}
	static void AddEnumTypes(params String[] names) {
		foreach (String name in names) Types.Add(name, new TypeInfo(name));
	}
	static void InitTypes() {
		Types.Add("short", new TypeInfo("Int16"));
		Types.Add("unsigned short", new TypeInfo("UInt16"));
		Types.Add("unsigned long", new TypeInfo("UInt32"));
		Types.Add("long long", new TypeInfo("Int64"));
		Types.Add("long", new TypeInfo("Int32"));
		Types.Add("octet", new TypeInfo("Byte"));
		Types.Add("unsigned long long", new TypeInfo("UInt32"));
		//Types.Add("boolean", new TypeInfo("Boolean", "MarshalAs(UnmanagedType.Bool)"));
		Types.Add("boolean", new TypeInfo("Int32"));
		Types.Add("wstring", new TypeInfo("String", "MarshalAs(UnmanagedType.LPWStr)"));
		//Types.Add("uuid", new TypeInfo("Guid", true, "MarshalAs(UnmanagedType.LPStruct)"));
		Types.Add("uuid", new TypeInfo("Guid", "MarshalAs(UnmanagedType.LPStruct)"));
		Types.Add("$unknown", new TypeInfo("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");
		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");
	}
	static void Main(string[] args) {
		InitTypes();

		XPathDocument doc = new XPathDocument("VirtualBox.xidl");
		XPathNavigator nav = doc.CreateNavigator();
		nav = nav.SelectSingleNode("/idl/library[@name='VirtualBox']");
		TextWriter o = Console.Out;
		o.WriteLine("using System;");
		o.WriteLine("using System.Runtime.CompilerServices;");
		o.WriteLine("using System.Runtime.InteropServices;");
		o.WriteLine("namespace VirtualBox {");
		foreach (XPathNavigator intf in nav.Select("interface")) {
			ProcessInterface(intf, o, nav);
		}
		foreach (XPathNavigator intf in nav.Select("enum")) {
			ProcessEnum(intf, o);
		}
		o.WriteLine("}");
	}
	static void ProcessEnum(XPathNavigator nav, TextWriter o) {
		String typeName = nav.SelectSingleNode("@name").Value;
		if (!Types.ContainsKey(typeName)) Types.Add(typeName, new TypeInfo(typeName));
		o.WriteLine("[Guid(\"{0}\")]", nav.SelectSingleNode("@uuid").Value);
		o.WriteLine("enum " + typeName + " {");
		foreach (XPathNavigator member in nav.SelectChildren(XPathNodeType.Element)) {
			switch (member.Name) {
				case "desc":
					break;
				case "const":
					o.WriteLine("\t{0} = {1},", member.SelectSingleNode("@name").Value, member.SelectSingleNode("@value").Value);
					break;
				default:
					Console.Error.WriteLine("Unknown member type {0}", member.Name);
					break;
			}
		}
		o.WriteLine("}");
	}
	static void ProcessInterface(XPathNavigator nav, TextWriter o, XPathNavigator parentNav) {
		String typeName = nav.SelectSingleNode("@name").Value;
		if (!Types.ContainsKey(typeName)) Types.Add(typeName, new TypeInfo(typeName, "MarshalAs(UnmanagedType.Interface)"));
		o.WriteLine("[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]");
		o.WriteLine("[Guid(\"{0}\")]", nav.SelectSingleNode("@uuid").Value);
		o.WriteLine("[ComImport()]");
		o.Write("interface " + typeName);
		o.WriteLine(" {");
		ProcessInterfaceMembersAndInherited(nav, o, parentNav);
		o.WriteLine("}");
	}
	static void ProcessInterfaceMembersAndInherited(XPathNavigator nav, TextWriter o, XPathNavigator parentNav) {
		XPathItem item = nav.SelectSingleNode("@extends");
		if (item != null && item.Value[0] != '$') {
			XPathNavigator inav = parentNav.SelectSingleNode("interface[@name='" + item.Value + "']");
			ProcessInterfaceMembersAndInherited(inav, o, parentNav);
		}
		ProcessInterfaceMembers(nav.SelectChildren(XPathNodeType.Element), o);
	}
	static void ProcessInterfaceMembers(XPathNodeIterator members, TextWriter oattribute) {
		XPathItem item;
		StringWriter omethod = new StringWriter();
		foreach (XPathNavigator member in members) {
			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";
						mName = mName.Substring(0, 1).ToUpper() + mName.Substring(1);
						oattribute.Write("\t");
						TypeInfo t = GetTypeDeclaration(member);
						oattribute.Write(t.Name);
						oattribute.Write(" ");
						oattribute.Write(mName);
						oattribute.WriteLine(" {");
						oattribute.Write("\t\t[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] ");
						t.WriteAttributes(oattribute, ParameterType.Return);
						oattribute.WriteLine("get;");
						if (!mReadOnly) {
							oattribute.Write("\t\t[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] ");
							t.WriteAttributes(oattribute, ParameterType.Param);
							oattribute.WriteLine("set;");
						}
						oattribute.WriteLine("\t}");
					} break;
				case "method": {
						String mName = member.SelectSingleNode("@name").Value;
						XPathNodeIterator mParamReturn = member.Select("param[@dir='return']");
						omethod.WriteLine("\t[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]");
						omethod.Write("\t");
						bool mReturn = false;
						if (mParamReturn == null || mParamReturn.Count != 1) {
							omethod.Write("void");
						} else {
							mParamReturn.MoveNext();
							mReturn = true;
							WriteTypeDeclaration(omethod, mParamReturn.Current, ParameterType.Return);
						}
						mName = mName.Substring(0, 1).ToUpper() + mName.Substring(1);
						omethod.Write(" ");
						omethod.Write(mName);
						omethod.Write("(");
						XPathNodeIterator mParams = member.Select("param");
						bool first = true;
						if (mParams.MoveNext()) {
							while (true) {
								XPathNavigator mParam = mParams.Current;
								String pDir = mParam.SelectSingleNode("@dir").Value;
								if (pDir == "return" && mReturn) {
									if (mParams.MoveNext()) {
										continue;
									} else {
										break;
									}
								} else if (pDir == "in") {
								} else if (pDir == "out") {
								} else {
									Console.Error.WriteLine("Unsupported parameter direction {0}", pDir);
								}
								if (first) {
									first = false;
								} else {
									omethod.Write(", ");
								}
								WriteTypeDeclaration(omethod, mParam, pDir == "out" ? ParameterType.Out : ParameterType.In);
								omethod.Write(" p");
								omethod.Write(mParam.SelectSingleNode("@name").Value);
								if (!mParams.MoveNext()) break;
							}
						}
						omethod.WriteLine(");");
					} break;
				default:
					Console.Error.WriteLine("Unknown member type {0}", member.Name);
					break;
			}
		}
		oattribute.Write((omethod as StringWriter).ToString());
	}
	private static TypeInfo GetTypeDeclaration(XPathNavigator nav) {
		ParameterType pt = ParameterType.Param;
		return GetTypeDeclaration(nav, ref pt);
	}
	private static void WriteTypeDeclaration(TextWriter o, XPathNavigator nav, ParameterType paramType) {
		TypeInfo t = GetTypeDeclaration(nav, ref paramType);
		t.WriteDeclaration(o, paramType);
	}
	private static 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)) {
			Console.Error.WriteLine("Type {0} is not supported", mType);
			t = new TypeInfo("void");
		}
		if (mMod == "ptr") {
			if (paramType == ParameterType.In) {
				paramType = ParameterType.Reference;
			} else {
				t = new TypeInfo("IntPtr");
			}
		} else if (mMod == "string") {
			t = new TypeInfo("String", "MarshalAs(UnmanagedType.LPWStr)");
		} else if (mMod != null) {
			Console.Error.WriteLine("Type modifier {0} is not supported", mMod);
			t = new TypeInfo("void");
		}
		if (pArray) {
			t = new TypeInfo("Array", "MarshalAs(UnmanagedType.SafeArray)");
			if (paramType == ParameterType.In || paramType == ParameterType.Out) paramType = ParameterType.Reference;
		}
		return t;
	}
}