Mercurial > hg > vboxdotnet
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