From 45277e93d8c8e18a04d1c28eb666337316726152 Mon Sep 17 00:00:00 2001 From: Owen Fraser-Green Date: Fri, 26 Mar 2004 15:25:59 +0000 Subject: Added signal support. --- mono/Connection.cs | 5 + mono/ErrorMessage.cs | 45 +++++++ mono/Handler.cs | 74 +++++------ mono/InterfaceProxy.cs | 45 ++++++- mono/Makefile.am | 2 + mono/Message.cs | 41 +++--- mono/ProxyBuilder.cs | 328 ++++++++++++++++++++++++++++++++++++++++++------ mono/Service.cs | 96 ++++++++++++-- mono/Signal.cs | 19 +++ mono/SignalAttribute.cs | 11 ++ 10 files changed, 552 insertions(+), 114 deletions(-) create mode 100644 mono/ErrorMessage.cs create mode 100644 mono/SignalAttribute.cs (limited to 'mono') diff --git a/mono/Connection.cs b/mono/Connection.cs index 406e779b..5e25ffd6 100644 --- a/mono/Connection.cs +++ b/mono/Connection.cs @@ -42,6 +42,11 @@ namespace DBus SetupWithMain(); } + public void Flush() + { + dbus_connection_flush(RawConnection); + } + public void SetupWithMain() { dbus_connection_setup_with_g_main(RawConnection, IntPtr.Zero); diff --git a/mono/ErrorMessage.cs b/mono/ErrorMessage.cs new file mode 100644 index 00000000..773a05b6 --- /dev/null +++ b/mono/ErrorMessage.cs @@ -0,0 +1,45 @@ +namespace DBus +{ + using System; + using System.Runtime.InteropServices; + using System.Diagnostics; + + public class ErrorMessage : Message + { + public ErrorMessage() : base(MessageType.Error) + { + } + + internal ErrorMessage(IntPtr rawMessage, Service service) : base(rawMessage, service) + { + } + + public ErrorMessage(Service service) : base(MessageType.Error, service) + { + } + + public new string Name + { + get { + if (this.name == null) { + this.name = Marshal.PtrToStringAnsi(dbus_message_get_error_name(RawMessage)); + } + + return this.name; + } + + set { + if (value != this.name) { + dbus_message_set_error_name(RawMessage, value); + this.name = value; + } + } + } + + [DllImport("dbus-1")] + private extern static bool dbus_message_set_error_name(IntPtr rawMessage, string name); + + [DllImport("dbus-1")] + private extern static IntPtr dbus_message_get_error_name(IntPtr rawMessage); + } +} diff --git a/mono/Handler.cs b/mono/Handler.cs index a854c9ce..be03dc5e 100644 --- a/mono/Handler.cs +++ b/mono/Handler.cs @@ -6,6 +6,13 @@ namespace DBus using System.Reflection; using System.Collections; + internal enum Result + { + Handled = 0, + NotYetHandled = 1, + NeedMemory = 2 + } + internal class Handler { private string[] path = null; @@ -15,7 +22,6 @@ namespace DBus private DBusObjectPathVTable vTable; private Connection connection; private Service service; - private DBusHandleMessageFunction filterCalled; internal delegate void DBusObjectPathUnregisterFunction(IntPtr rawConnection, IntPtr userData); @@ -24,18 +30,6 @@ namespace DBus IntPtr rawMessage, IntPtr userData); - internal delegate int DBusHandleMessageFunction(IntPtr rawConnection, - IntPtr rawMessage, - IntPtr userData); - - - private enum Result - { - Handled = 0, - NotYetHandled = 1, - NeedMemory = 2 - } - [StructLayout (LayoutKind.Sequential)] private struct DBusObjectPathVTable { @@ -67,8 +61,8 @@ namespace DBus } public Handler(object handledObject, - string pathName, - Service service) + string pathName, + Service service) { Service = service; Connection = service.Connection; @@ -88,14 +82,22 @@ namespace DBus ref vTable, IntPtr.Zero)) throw new OutOfMemoryException(); - - // Setup the filter function - this.filterCalled = new DBusHandleMessageFunction(Filter_Called); - if (!dbus_connection_add_filter(Connection.RawConnection, - this.filterCalled, - IntPtr.Zero, - IntPtr.Zero)) - throw new OutOfMemoryException(); + + RegisterSignalHandlers(); + } + + private void RegisterSignalHandlers() + { + ProxyBuilder proxyBuilder = new ProxyBuilder(Service, HandledObject.GetType(), this.pathName); + + foreach (DictionaryEntry interfaceEntry in this.introspector.InterfaceProxies) { + InterfaceProxy interfaceProxy = (InterfaceProxy) interfaceEntry.Value; + foreach (DictionaryEntry signalEntry in interfaceProxy.Signals) { + EventInfo eventE = (EventInfo) signalEntry.Value; + Delegate del = Delegate.CreateDelegate(eventE.EventHandlerType, proxyBuilder.GetSignalProxy(), "Proxy_" + eventE.Name); + eventE.AddEventHandler(HandledObject, del); + } + } } public object HandledObject @@ -113,21 +115,6 @@ namespace DBus this.introspector = Introspector.GetIntrospector(value.GetType()); } } - - public int Filter_Called(IntPtr rawConnection, - IntPtr rawMessage, - IntPtr userData) - { - Message message = Message.Wrap(rawMessage, Service); - - if (message.Type == Message.MessageType.Signal) { - Signal signal = (Signal) message; - } else if (message.Type == Message.MessageType.MethodCall) { - MethodCall methodCall = (MethodCall) message; - } - - return (int) Result.NotYetHandled; - } public void Unregister_Called(IntPtr rawConnection, IntPtr userData) @@ -143,7 +130,8 @@ namespace DBus switch (message.Type) { case Message.MessageType.Signal: - System.Console.WriteLine("FIXME: Signal called."); + // We're not interested in signals here because we're the ones + // that generate them! break; case Message.MessageType.MethodCall: return (int) HandleMethod((MethodCall) message); @@ -216,7 +204,7 @@ namespace DBus { this.service = value; } - } + } [DllImport ("dbus-1")] private extern static bool dbus_connection_register_object_path (IntPtr rawConnection, string[] path, ref DBusObjectPathVTable vTable, IntPtr userData); @@ -224,11 +212,5 @@ namespace DBus [DllImport ("dbus-1")] private extern static void dbus_connection_unregister_object_path (IntPtr rawConnection, string[] path); - [DllImport ("dbus-1")] - private extern static bool dbus_connection_add_filter(IntPtr rawConnection, - DBusHandleMessageFunction filter, - IntPtr userData, - IntPtr freeData); - } } diff --git a/mono/InterfaceProxy.cs b/mono/InterfaceProxy.cs index 6ccc9636..50697738 100644 --- a/mono/InterfaceProxy.cs +++ b/mono/InterfaceProxy.cs @@ -8,7 +8,8 @@ namespace DBus { private static Hashtable interfaceProxies = new Hashtable(); private Hashtable methods = null; - + private Hashtable signals = null; + private string interfaceName; private InterfaceProxy(Type type) @@ -17,17 +18,34 @@ namespace DBus InterfaceAttribute interfaceAttribute = (InterfaceAttribute) attributes[0]; this.interfaceName = interfaceAttribute.InterfaceName; AddMethods(type); + AddSignals(type); } + // Add all the events with Signal attributes + private void AddSignals(Type type) + { + this.signals = new Hashtable(); + foreach (EventInfo signal in type.GetEvents(BindingFlags.Public | + BindingFlags.Instance | + BindingFlags.DeclaredOnly)) { + object[] attributes = signal.GetCustomAttributes(typeof(SignalAttribute), false); + if (attributes.GetLength(0) > 0) { + MethodInfo invoke = signal.EventHandlerType.GetMethod("Invoke"); + signals.Add(signal.Name + " " + GetSignature(invoke), signal); + } + } + } + + // Add all the methods with Method attributes private void AddMethods(Type type) { this.methods = new Hashtable(); foreach (MethodInfo method in type.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly)) { - object[] attributes = method.GetCustomAttributes(typeof(MethodAttribute), true); + object[] attributes = method.GetCustomAttributes(typeof(MethodAttribute), false); if (attributes.GetLength(0) > 0) { - methods.Add(GetKey(method), method); + methods.Add(method.Name + " " + GetSignature(method), method); } } } @@ -46,16 +64,26 @@ namespace DBus { return this.Methods.Contains(key); } + + public bool HasSignal(string key) + { + return this.Signals.Contains(key); + } + + public EventInfo GetSignal(string key) + { + return (EventInfo) this.Signals[key]; + } public MethodInfo GetMethod(string key) { return (MethodInfo) this.Methods[key]; } - private string GetKey(MethodInfo method) + public static string GetSignature(MethodInfo method) { ParameterInfo[] pars = method.GetParameters(); - string key = method.Name + " "; + string key = ""; foreach (ParameterInfo par in pars) { if (!par.IsOut) { @@ -73,6 +101,13 @@ namespace DBus return this.methods; } } + + public Hashtable Signals + { + get { + return this.signals; + } + } public string InterfaceName { diff --git a/mono/Makefile.am b/mono/Makefile.am index b35a5c42..6efd771a 100644 --- a/mono/Makefile.am +++ b/mono/Makefile.am @@ -10,6 +10,7 @@ DBUS_SHARP_FILES= \ Custom.cs \ DBusException.cs \ Error.cs \ + ErrorMessage.cs \ Handler.cs \ InterfaceAttribute.cs \ InterfaceProxy.cs \ @@ -22,6 +23,7 @@ DBUS_SHARP_FILES= \ Server.cs \ Service.cs \ Signal.cs \ + SignalAttribute.cs \ DBusType/IDBusType.cs \ DBusType/Array.cs \ DBusType/Boolean.cs \ diff --git a/mono/Message.cs b/mono/Message.cs index a1ff220c..54472d1e 100644 --- a/mono/Message.cs +++ b/mono/Message.cs @@ -80,14 +80,23 @@ namespace DBus } // If it doesn't exist then create a new Message around it Message message = null; + MessageType messageType = (MessageType) dbus_message_get_type(rawMessage); - switch ((MessageType) dbus_message_get_type(rawMessage)) { + switch (messageType) { case MessageType.Signal: message = new Signal(rawMessage, service); break; case MessageType.MethodCall: message = new MethodCall(rawMessage, service); break; + case MessageType.MethodReturn: + message = new MethodReturn(rawMessage, service); + break; + case MessageType.Error: + message = new ErrorMessage(rawMessage, service); + break; + default: + throw new ApplicationException("Unknown message type to wrap: " + messageType); } return message; @@ -140,6 +149,8 @@ namespace DBus { if (!dbus_connection_send (Service.Connection.RawConnection, RawMessage, ref serial)) throw new OutOfMemoryException (); + + Service.Connection.Flush(); } public void Send() @@ -245,23 +256,19 @@ namespace DBus protected virtual string Name { - set - { - if (value != this.name) - { - dbus_message_set_member (RawMessage, value); - this.name = value; - } + set { + if (value != this.name) { + dbus_message_set_member(RawMessage, value); + this.name = value; } - get - { - if (this.name == null) { - this.name = Marshal.PtrToStringAnsi(dbus_message_get_member(RawMessage)); - } - - - return this.name; + } + get { + if (this.name == null) { + this.name = Marshal.PtrToStringAnsi(dbus_message_get_member(RawMessage)); } + + return this.name; + } } public string Key @@ -356,7 +363,7 @@ namespace DBus private extern static IntPtr dbus_message_get_interface(IntPtr rawMessage); [DllImport("dbus-1")] - private extern static bool dbus_message_set_member (IntPtr rawMessage, string name); + private extern static bool dbus_message_set_member(IntPtr rawMessage, string name); [DllImport("dbus-1")] private extern static IntPtr dbus_message_get_member(IntPtr rawMessage); diff --git a/mono/ProxyBuilder.cs b/mono/ProxyBuilder.cs index 4ef2fe91..80449093 100644 --- a/mono/ProxyBuilder.cs +++ b/mono/ProxyBuilder.cs @@ -14,20 +14,27 @@ namespace DBus private string pathName = null; private Type type = null; private Introspector introspector = null; - private static AssemblyBuilder proxyAssembly; private static MethodInfo Service_NameMI = typeof(Service).GetMethod("get_Name", new Type[0]); private static MethodInfo Service_ConnectionMI = typeof(Service).GetMethod("get_Connection", new Type[0]); + private static MethodInfo Service_AddSignalCalledMI = typeof(Service).GetMethod("add_SignalCalled", + new Type[] {typeof(Service.SignalCalledHandler)}); + private static MethodInfo Signal_PathNameMI = typeof(Signal).GetMethod("get_PathName", + new Type[0]); private static MethodInfo Message_ArgumentsMI = typeof(Message).GetMethod("get_Arguments", new Type[0]); + private static MethodInfo Message_KeyMI = typeof(Message).GetMethod("get_Key", + new Type[0]); private static MethodInfo Arguments_InitAppendingMI = typeof(Arguments).GetMethod("InitAppending", new Type[0]); private static MethodInfo Arguments_AppendMI = typeof(Arguments).GetMethod("Append", new Type[] {typeof(DBusType.IDBusType)}); private static MethodInfo Message_SendWithReplyAndBlockMI = typeof(Message).GetMethod("SendWithReplyAndBlock", new Type[0]); + private static MethodInfo Message_SendMI = typeof(Message).GetMethod("Send", + new Type[0]); private static MethodInfo Arguments_GetEnumeratorMI = typeof(Arguments).GetMethod("GetEnumerator", new Type[0]); private static MethodInfo IEnumerator_MoveNextMI = typeof(System.Collections.IEnumerator).GetMethod("MoveNext", @@ -42,8 +49,19 @@ namespace DBus typeof(string), typeof(string), typeof(string)}); + private static ConstructorInfo Signal_C = typeof(Signal).GetConstructor(new Type[] {typeof(Service), + typeof(string), + typeof(string), + typeof(string)}); + private static ConstructorInfo Service_SignalCalledHandlerC = typeof(Service.SignalCalledHandler).GetConstructor(new Type[] {typeof(object), + typeof(System.IntPtr)}); + private static MethodInfo String_opEqualityMI = typeof(System.String).GetMethod("op_Equality", + new Type[] {typeof(string), + typeof(string)}); + private static MethodInfo MulticastDelegate_opInequalityMI = typeof(System.MulticastDelegate).GetMethod("op_Inequality", + new Type[] {typeof(System.MulticastDelegate), + typeof(System.MulticastDelegate)}); - public ProxyBuilder(Service service, Type type, string pathName) { @@ -53,6 +71,163 @@ namespace DBus this.introspector = Introspector.GetIntrospector(type); } + private MethodInfo BuildSignalCalled(ref TypeBuilder typeB, FieldInfo serviceF, FieldInfo pathF) + { + Type[] parTypes = {typeof(Signal)}; + MethodBuilder methodBuilder = typeB.DefineMethod("Service_SignalCalled", + MethodAttributes.Private | + MethodAttributes.HideBySig, + typeof(void), + parTypes); + + ILGenerator generator = methodBuilder.GetILGenerator(); + + LocalBuilder enumeratorL = generator.DeclareLocal(typeof(System.Collections.IEnumerator)); + enumeratorL.SetLocalSymInfo("enumerator"); + + Label wrongPath = generator.DefineLabel(); + //generator.EmitWriteLine("if (signal.PathName == pathName) {"); + generator.Emit(OpCodes.Ldarg_1); + generator.EmitCall(OpCodes.Callvirt, Signal_PathNameMI, null); + generator.Emit(OpCodes.Ldarg_0); + generator.Emit(OpCodes.Ldfld, pathF); + generator.EmitCall(OpCodes.Call, String_opEqualityMI, null); + generator.Emit(OpCodes.Brfalse, wrongPath); + + int localOffset = 1; + + foreach (DictionaryEntry interfaceEntry in this.introspector.InterfaceProxies) { + InterfaceProxy interfaceProxy = (InterfaceProxy) interfaceEntry.Value; + foreach (DictionaryEntry signalEntry in interfaceProxy.Signals) { + EventInfo eventE = (EventInfo) signalEntry.Value; + // This is really cheeky since we need to grab the event as a private field. + FieldInfo eventF = this.type.GetField(eventE.Name, + BindingFlags.NonPublic| + BindingFlags.Instance); + + MethodInfo eventHandler_InvokeMI = eventE.EventHandlerType.GetMethod("Invoke"); + + ParameterInfo[] pars = eventHandler_InvokeMI.GetParameters(); + parTypes = new Type[pars.Length]; + for (int parN = 0; parN < pars.Length; parN++) { + parTypes[parN] = pars[parN].ParameterType; + LocalBuilder parmL = generator.DeclareLocal(parTypes[parN]); + parmL.SetLocalSymInfo(pars[parN].Name); + } + + Label skip = generator.DefineLabel(); + //generator.EmitWriteLine(" if (SelectedIndexChanged != null) {"); + generator.Emit(OpCodes.Ldarg_0); + generator.Emit(OpCodes.Ldfld, eventF); + generator.Emit(OpCodes.Ldnull); + generator.EmitCall(OpCodes.Call, MulticastDelegate_opInequalityMI, null); + generator.Emit(OpCodes.Brfalse, skip); + + //generator.EmitWriteLine(" if (signal.Key == 'la i')"); + generator.Emit(OpCodes.Ldarg_1); + generator.EmitCall(OpCodes.Callvirt, Message_KeyMI, null); + generator.Emit(OpCodes.Ldstr, eventE.Name + " " + InterfaceProxy.GetSignature(eventHandler_InvokeMI)); + generator.EmitCall(OpCodes.Call, String_opEqualityMI, null); + generator.Emit(OpCodes.Brfalse, skip); + + //generator.EmitWriteLine("IEnumerator enumerator = signal.Arguments.GetEnumerator()"); + generator.Emit(OpCodes.Ldarg_1); + generator.EmitCall(OpCodes.Callvirt, Message_ArgumentsMI, null); + generator.EmitCall(OpCodes.Callvirt, Arguments_GetEnumeratorMI, null); + generator.Emit(OpCodes.Stloc_0); + + for (int parN = 0; parN < pars.Length; parN++) { + ParameterInfo par = pars[parN]; + if (!par.IsOut) { + EmitSignalIn(generator, par.ParameterType, parN + localOffset, serviceF); + } + } + + //generator.EmitWriteLine(" SelectedIndexChanged(selectedIndex)"); + generator.Emit(OpCodes.Ldarg_0); + generator.Emit(OpCodes.Ldfld, eventF); + for (int parN = 0; parN < pars.Length; parN++) { + generator.Emit(OpCodes.Ldloc_S, parN + localOffset); + } + + generator.EmitCall(OpCodes.Callvirt, eventHandler_InvokeMI, null); + + generator.MarkLabel(skip); + //generator.EmitWriteLine(" }"); + + localOffset += pars.Length; + } + } + + generator.MarkLabel(wrongPath); + //generator.EmitWriteLine("}"); + + //generator.EmitWriteLine("return"); + generator.Emit(OpCodes.Ret); + + return methodBuilder; + } + + private void BuildSignalHandler(EventInfo eventE, + InterfaceProxy interfaceProxy, + ref TypeBuilder typeB, + FieldInfo serviceF, + FieldInfo pathF) + { + MethodInfo eventHandler_InvokeMI = eventE.EventHandlerType.GetMethod("Invoke"); + ParameterInfo[] pars = eventHandler_InvokeMI.GetParameters(); + Type[] parTypes = new Type[pars.Length]; + for (int parN = 0; parN < pars.Length; parN++) { + parTypes[parN] = pars[parN].ParameterType; + } + + // Generate the code + MethodBuilder methodBuilder = typeB.DefineMethod("Proxy_" + eventE.Name, + MethodAttributes.Public | + MethodAttributes.HideBySig | + MethodAttributes.Virtual, + typeof(void), + parTypes); + ILGenerator generator = methodBuilder.GetILGenerator(); + + for (int parN = 0; parN < pars.Length; parN++) { + methodBuilder.DefineParameter(parN + 1, pars[parN].Attributes, pars[parN].Name); + } + + // Generate the locals + LocalBuilder methodCallL = generator.DeclareLocal(typeof(MethodCall)); + methodCallL.SetLocalSymInfo("signal"); + LocalBuilder replyL = generator.DeclareLocal(typeof(MethodReturn)); + + //generator.EmitWriteLine("Signal signal = new Signal(...)"); + generator.Emit(OpCodes.Ldsfld, serviceF); + generator.Emit(OpCodes.Ldarg_0); + generator.Emit(OpCodes.Ldfld, pathF); + generator.Emit(OpCodes.Ldstr, interfaceProxy.InterfaceName); + generator.Emit(OpCodes.Ldstr, eventE.Name); + generator.Emit(OpCodes.Newobj, Signal_C); + generator.Emit(OpCodes.Stloc_0); + + //generator.EmitWriteLine("signal.Arguments.InitAppending()"); + generator.Emit(OpCodes.Ldloc_0); + generator.EmitCall(OpCodes.Callvirt, Message_ArgumentsMI, null); + generator.EmitCall(OpCodes.Callvirt, Arguments_InitAppendingMI, null); + + for (int parN = 0; parN < pars.Length; parN++) { + ParameterInfo par = pars[parN]; + if (!par.IsOut) { + EmitIn(generator, par.ParameterType, parN, serviceF); + } + } + + //generator.EmitWriteLine("signal.Send()"); + generator.Emit(OpCodes.Ldloc_0); + generator.EmitCall(OpCodes.Callvirt, Message_SendMI, null); + + //generator.EmitWriteLine("return"); + generator.Emit(OpCodes.Ret); + } + private void BuildMethod(MethodInfo method, InterfaceProxy interfaceProxy, ref TypeBuilder typeB, @@ -145,6 +320,28 @@ namespace DBus typeB.DefineMethodOverride(methodBuilder, method); } + private void EmitSignalIn(ILGenerator generator, Type parType, int parN, FieldInfo serviceF) + { + //generator.EmitWriteLine("enumerator.MoveNext()"); + generator.Emit(OpCodes.Ldloc_0); + generator.EmitCall(OpCodes.Callvirt, IEnumerator_MoveNextMI, null); + + Type outParType = Arguments.MatchType(parType); + //generator.EmitWriteLine("int selectedIndex = (int) ((DBusType.IDBusType) enumerator.Current).Get(typeof(int))"); + generator.Emit(OpCodes.Pop); + generator.Emit(OpCodes.Ldloc_0); + generator.EmitCall(OpCodes.Callvirt, IEnumerator_CurrentMI, null); + generator.Emit(OpCodes.Castclass, typeof(DBusType.IDBusType)); + generator.Emit(OpCodes.Ldtoken, parType); + generator.EmitCall(OpCodes.Call, Type_GetTypeFromHandleMI, null); + generator.EmitCall(OpCodes.Callvirt, IDBusType_GetMI, null); + // Call the DBusType EmitMarshalOut to make it emit itself + object[] pars = new object[] {generator, parType, true}; + outParType.InvokeMember("EmitMarshalOut", BindingFlags.Static | BindingFlags.Public | BindingFlags.InvokeMethod, null, null, pars, null); + generator.Emit(OpCodes.Stloc_S, parN); + } + + private void EmitIn(ILGenerator generator, Type parType, int parN, FieldInfo serviceF) { Type inParType = Arguments.MatchType(parType); @@ -191,7 +388,7 @@ namespace DBus } } - public void BuildConstructor(ref TypeBuilder typeB, FieldInfo serviceF, FieldInfo pathF) + public void BuildConstructor(ref TypeBuilder typeB, FieldInfo serviceF, FieldInfo pathF, MethodInfo signalCalledMI) { Type[] pars = {typeof(Service), typeof(string)}; ConstructorBuilder constructor = typeB.DefineConstructor(MethodAttributes.RTSpecialName | @@ -201,23 +398,102 @@ namespace DBus ILGenerator generator = constructor.GetILGenerator(); generator.Emit(OpCodes.Ldarg_0); generator.Emit(OpCodes.Call, this.introspector.Constructor); + //generator.EmitWriteLine("service = myService"); generator.Emit(OpCodes.Ldarg_1); generator.Emit(OpCodes.Stsfld, serviceF); + //generator.EmitWriteLine("this.pathName = pathName"); generator.Emit(OpCodes.Ldarg_0); generator.Emit(OpCodes.Ldarg_2); generator.Emit(OpCodes.Stfld, pathF); + + //generator.EmitWriteLine("myService.SignalCalled += new Service.SignalCalledHandler(Service_SignalCalled)"); + generator.Emit(OpCodes.Ldarg_1); + generator.Emit(OpCodes.Ldarg_0); + generator.Emit(OpCodes.Ldftn, signalCalledMI); + generator.Emit(OpCodes.Newobj, Service_SignalCalledHandlerC); + generator.EmitCall(OpCodes.Callvirt, Service_AddSignalCalledMI, null); + //generator.EmitWriteLine("return"); + generator.Emit(OpCodes.Ret); + } + + public void BuildSignalConstructor(ref TypeBuilder typeB, FieldInfo serviceF, FieldInfo pathF) + { + Type[] pars = {typeof(Service), typeof(string)}; + ConstructorBuilder constructor = typeB.DefineConstructor(MethodAttributes.RTSpecialName | + MethodAttributes.Public, + CallingConventions.Standard, pars); + + ILGenerator generator = constructor.GetILGenerator(); + generator.Emit(OpCodes.Ldarg_0); + generator.Emit(OpCodes.Call, this.introspector.Constructor); + //generator.EmitWriteLine("service = myService"); + generator.Emit(OpCodes.Ldarg_1); + generator.Emit(OpCodes.Stsfld, serviceF); + //generator.EmitWriteLine("this.pathName = pathName"); + generator.Emit(OpCodes.Ldarg_0); + generator.Emit(OpCodes.Ldarg_2); + generator.Emit(OpCodes.Stfld, pathF); + + //generator.EmitWriteLine("return"); generator.Emit(OpCodes.Ret); } - public object GetProxy() - { + public object GetSignalProxy() + { + Type proxyType = Service.ProxyAssembly.GetType(ObjectName + ".SignalProxy"); + + if (proxyType == null) { + // Build the type + TypeBuilder typeB = Service.Module.DefineType(ObjectName + ".SignalProxy", + TypeAttributes.Public, + this.type); + + FieldBuilder serviceF = typeB.DefineField("service", + typeof(Service), + FieldAttributes.Private | + FieldAttributes.Static); + FieldBuilder pathF = typeB.DefineField("pathName", + typeof(string), + FieldAttributes.Private); + + BuildSignalConstructor(ref typeB, serviceF, pathF); + + // Build the signal handlers + foreach (DictionaryEntry interfaceEntry in this.introspector.InterfaceProxies) { + InterfaceProxy interfaceProxy = (InterfaceProxy) interfaceEntry.Value; + foreach (DictionaryEntry signalEntry in interfaceProxy.Signals) { + EventInfo eventE = (EventInfo) signalEntry.Value; + BuildSignalHandler(eventE, interfaceProxy, ref typeB, serviceF, pathF); + } + } + + proxyType = typeB.CreateType(); - Type proxyType = ProxyAssembly.GetType(ProxyName); + // Uncomment the following line to produce a DLL of the + // constructed assembly which can then be examined using + // monodis. Note that in order for this to work you should copy + // the client assembly as a dll file so that monodis can pick it + // up. + //Service.ProxyAssembly.Save("proxy.dll"); + } + + Type [] parTypes = new Type[] {typeof(Service), typeof(string)}; + object [] pars = new object[] {Service, pathName}; + + ConstructorInfo constructor = proxyType.GetConstructor(parTypes); + object instance = constructor.Invoke(pars); + return instance; + } + + + public object GetProxy() + { + Type proxyType = Service.ProxyAssembly.GetType(ObjectName + ".Proxy"); if (proxyType == null) { // Build the type - TypeBuilder typeB = ServiceModuleBuilder.DefineType(ProxyName, TypeAttributes.Public, this.type); + TypeBuilder typeB = Service.Module.DefineType(ObjectName + ".Proxy", TypeAttributes.Public, this.type); FieldBuilder serviceF = typeB.DefineField("service", typeof(Service), @@ -227,7 +503,8 @@ namespace DBus typeof(string), FieldAttributes.Private); - BuildConstructor(ref typeB, serviceF, pathF); + MethodInfo signalCalledMI = BuildSignalCalled(ref typeB, serviceF, pathF); + BuildConstructor(ref typeB, serviceF, pathF, signalCalledMI); // Build the methods foreach (DictionaryEntry interfaceEntry in this.introspector.InterfaceProxies) { @@ -245,7 +522,7 @@ namespace DBus // monodis. Note that in order for this to work you should copy // the client assembly as a dll file so that monodis can pick it // up. - //ProxyAssembly.Save("proxy.dll"); + //Service.ProxyAssembly.Save("proxy.dll"); } Type [] parTypes = new Type[] {typeof(Service), typeof(string)}; @@ -255,43 +532,18 @@ namespace DBus object instance = constructor.Invoke(pars); return instance; } - - private ModuleBuilder ServiceModuleBuilder - { - get { - if (Service.module == null) { - Service.module = ProxyAssembly.DefineDynamicModule(Service.Name, "proxy.dll", true); - } - - return Service.module; - } - } - - private Service Service + + private Service Service { get { return this.service; } } - private string ProxyName + private string ObjectName { get { - return this.introspector.ToString() + ".Proxy"; - } - } - - private AssemblyBuilder ProxyAssembly - { - get { - if (proxyAssembly == null){ - AssemblyName assemblyName = new AssemblyName(); - assemblyName.Name = "DBusProxy"; - proxyAssembly = Thread.GetDomain().DefineDynamicAssembly(assemblyName, - AssemblyBuilderAccess.RunAndSave); - } - - return proxyAssembly; + return this.introspector.ToString(); } } } diff --git a/mono/Service.cs b/mono/Service.cs index 16e52d19..c34ba3dc 100644 --- a/mono/Service.cs +++ b/mono/Service.cs @@ -4,6 +4,7 @@ namespace DBus using System.Runtime.InteropServices; using System.Diagnostics; using System.Collections; + using System.Threading; using System.Reflection; using System.Reflection.Emit; @@ -13,12 +14,20 @@ namespace DBus private string name; private bool local = false; private Hashtable registeredHandlers = new Hashtable(); - internal ModuleBuilder module = null; + private delegate int DBusHandleMessageFunction(IntPtr rawConnection, + IntPtr rawMessage, + IntPtr userData); + private DBusHandleMessageFunction filterCalled; + public delegate void SignalCalledHandler(Signal signal); + public event SignalCalledHandler SignalCalled; + private static AssemblyBuilder proxyAssembly; + private ModuleBuilder module = null; internal Service(string name, Connection connection) { this.name = name; this.connection = connection; + AddFilter(); } public Service(Connection connection, string name) @@ -67,9 +76,7 @@ namespace DBus public void RegisterObject(object handledObject, string pathName) { - Handler handler = new Handler(handledObject, - pathName, - this); + Handler handler = new Handler(handledObject, pathName, this); registeredHandlers.Add(handledObject, handler); } @@ -89,6 +96,38 @@ namespace DBus return proxy; } + private void AddFilter() + { + // Setup the filter function + this.filterCalled = new DBusHandleMessageFunction(Service_FilterCalled); + if (!dbus_connection_add_filter(Connection.RawConnection, + this.filterCalled, + IntPtr.Zero, + IntPtr.Zero)) + throw new OutOfMemoryException(); + + // Add a match for signals. FIXME: Can we filter the service? + string rule = "type='signal'"; + dbus_bus_add_match(connection.RawConnection, rule, IntPtr.Zero); + } + + private int Service_FilterCalled(IntPtr rawConnection, + IntPtr rawMessage, + IntPtr userData) + { + Message message = Message.Wrap(rawMessage, this); + + if (message.Type == Message.MessageType.Signal) { + // We're only interested in signals + Signal signal = (Signal) message; + if (SignalCalled != null) { + SignalCalled(signal); + } + } + + return (int) Result.NotYetHandled; + } + public string Name { get @@ -110,10 +149,51 @@ namespace DBus } } - [DllImport ("dbus-1")] - private extern static int dbus_bus_acquire_service (IntPtr rawConnection, string serviceName, uint flags, ref Error error); + internal AssemblyBuilder ProxyAssembly + { + get { + if (proxyAssembly == null){ + AssemblyName assemblyName = new AssemblyName(); + assemblyName.Name = "DBusProxy"; + proxyAssembly = Thread.GetDomain().DefineDynamicAssembly(assemblyName, + AssemblyBuilderAccess.RunAndSave); + } + + return proxyAssembly; + } + } + + internal ModuleBuilder Module + { + get { + if (this.module == null) { + this.module = ProxyAssembly.DefineDynamicModule(Name, "proxy.dll", true); + } + + return this.module; + } + } + + [DllImport("dbus-1")] + private extern static int dbus_bus_acquire_service(IntPtr rawConnection, + string serviceName, + uint flags, ref Error error); + + [DllImport("dbus-1")] + private extern static bool dbus_bus_service_exists(IntPtr rawConnection, + string serviceName, + ref Error error); + + [DllImport("dbus-1")] + private extern static bool dbus_connection_add_filter(IntPtr rawConnection, + DBusHandleMessageFunction filter, + IntPtr userData, + IntPtr freeData); + + [DllImport("dbus-1")] + private extern static void dbus_bus_add_match(IntPtr rawConnection, + string rule, + IntPtr erro); - [DllImport ("dbus-1")] - private extern static bool dbus_bus_service_exists (IntPtr rawConnection, string serviceName, ref Error error); } } diff --git a/mono/Signal.cs b/mono/Signal.cs index a9209fec..10191f9d 100644 --- a/mono/Signal.cs +++ b/mono/Signal.cs @@ -18,6 +18,23 @@ namespace DBus { } + public Signal(Service service, string pathName, string interfaceName, string name) + { + this.service = service; + + RawMessage = dbus_message_new_signal(pathName, interfaceName, name); + + if (RawMessage == IntPtr.Zero) { + throw new OutOfMemoryException(); + } + + this.pathName = pathName; + this.interfaceName = interfaceName; + this.name = name; + + dbus_message_unref(RawMessage); + } + public new string PathName { get @@ -56,5 +73,7 @@ namespace DBus base.Name = value; } } + [DllImport("dbus-1")] + private extern static IntPtr dbus_message_new_signal(string pathName, string interfaceName, string name); } } diff --git a/mono/SignalAttribute.cs b/mono/SignalAttribute.cs new file mode 100644 index 00000000..4835444b --- /dev/null +++ b/mono/SignalAttribute.cs @@ -0,0 +1,11 @@ +using System; + +namespace DBus +{ + [AttributeUsage(AttributeTargets.Event, AllowMultiple=false, Inherited=true)] public class SignalAttribute : Attribute + { + public SignalAttribute() + { + } + } +} -- cgit