summaryrefslogtreecommitdiffstats
path: root/mono
diff options
context:
space:
mode:
authorOwen Fraser-Green <owen@discobabe.net>2004-03-26 15:25:59 +0000
committerOwen Fraser-Green <owen@discobabe.net>2004-03-26 15:25:59 +0000
commit45277e93d8c8e18a04d1c28eb666337316726152 (patch)
tree46502f3644fad7cad6932e3d3267edf3a4a42eec /mono
parent7dd57040236dc34a313948f75b403a49df693649 (diff)
Added signal support.
Diffstat (limited to 'mono')
-rw-r--r--mono/Connection.cs5
-rw-r--r--mono/ErrorMessage.cs45
-rw-r--r--mono/Handler.cs74
-rw-r--r--mono/InterfaceProxy.cs45
-rw-r--r--mono/Makefile.am2
-rw-r--r--mono/Message.cs41
-rw-r--r--mono/ProxyBuilder.cs328
-rw-r--r--mono/Service.cs96
-rw-r--r--mono/Signal.cs19
-rw-r--r--mono/SignalAttribute.cs11
10 files changed, 552 insertions, 114 deletions
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()
+ {
+ }
+ }
+}