diff InteropCodeGen/XidlParser.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
line wrap: on
line diff
--- /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