diff --git a/src/ExportObject.cs b/src/ExportObject.cs index 06f25f7..620de6c 100644 --- a/src/ExportObject.cs +++ b/src/ExportObject.cs @@ -28,7 +28,9 @@ internal class MethodCall { } internal class MethodDictionary : Dictionary { } - internal class PropertyDictionary : Dictionary { } + internal class PropertyDictionary : Dictionary { + public MethodCaller All { get; set; } + } internal class InterfaceMethods : Dictionary { } internal class InterfaceProperties : Dictionary { } @@ -59,6 +61,21 @@ public MethodCall GetMethodCall (string iface, string name) ); } + public MethodCaller GetPropertyAllCall (string iface) + { + PropertyDictionary calls; + if (!Properties.TryGetValue(iface, out calls)) { + Properties [iface] = calls = new PropertyDictionary (); + } + + if (null == calls.All) { + Type it = Mapper.GetInterfaceType (ObjectType, iface); + calls.All = TypeImplementer.GenGetAllCall (it); + } + + return calls.All; + } + public PropertyCall GetPropertyCall (string iface, string name) { return Lookup ( @@ -238,8 +255,17 @@ private void HandlePropertyCall (MessageContainer method_call) string face = (string) args [0]; if ("GetAll" == method_call.Member) { - // TODO - throw new NotImplementedException (); + Signature asv = Signature.MakeDict (Signature.StringSig, Signature.VariantSig); + + MethodCaller call = typeMembers [Object.GetType ()].GetPropertyAllCall (face); + + Exception ex = null; + try { + call (Object, msgReader, msg, retWriter); + } catch (Exception e) { ex = e; } + + IssueReply (method_call, asv, retWriter, null, ex); + return; } string name = (string) args [1]; diff --git a/src/TypeImplementer.cs b/src/TypeImplementer.cs index f67a7af..2b3b60a 100644 --- a/src/TypeImplementer.cs +++ b/src/TypeImplementer.cs @@ -622,6 +622,55 @@ internal static MethodCaller GenSetCall (PropertyInfo target) return (MethodCaller) method.CreateDelegate (typeof(MethodCaller)); } + internal static MethodCaller GenGetAllCall (Type @interface) + { + var parms = new Type[] { + typeof (object), + typeof (MessageReader), + typeof (Message), + typeof (MessageWriter) + }; + var method = new DynamicMethod ("PropertyGetAll", typeof(void), parms, typeof(MessageReader)); + + var ilg = method.GetILGenerator (); + var dctT = typeof(Dictionary); + + var strObj = new [] { typeof(string), typeof(object) }; + var dctConstructor = dctT.GetConstructor (new Type[0]); + var dctAdd = dctT.GetMethod ("Add", strObj); + + var accessors = @interface.GetProperties ().Where (x => null != x.GetGetMethod()); + + var dct = ilg.DeclareLocal (dctT); + var val = ilg.DeclareLocal (typeof(object)); + + ilg.Emit (OpCodes.Newobj, dctConstructor); + ilg.Emit (OpCodes.Stloc, dct); + foreach (var property in accessors) { + var mi = property.GetGetMethod (); + + ilg.Emit (OpCodes.Ldarg_0); + ilg.Emit (mi.IsFinal ? OpCodes.Call : OpCodes.Callvirt, mi); + if (mi.ReturnType.IsValueType) { + ilg.Emit (OpCodes.Box, mi.ReturnType); + } + // TODO: Cast object references to typeof(object)? + ilg.Emit (OpCodes.Stloc, val); + + ilg.Emit (OpCodes.Ldloc, dct); + ilg.Emit (OpCodes.Ldstr, property.Name); + ilg.Emit (OpCodes.Ldloc, val); + ilg.Emit (OpCodes.Call, dctAdd); + } + ilg.Emit (OpCodes.Ldarg_3); + ilg.Emit (OpCodes.Ldloc, dct); + GenWriter (ilg, dctT); + + ilg.Emit (OpCodes.Ret); + + return (MethodCaller) method.CreateDelegate (typeof(MethodCaller)); + } + internal static MethodCaller GenCaller (MethodInfo target) { DynamicMethod hookupMethod = GenReadMethod (target); diff --git a/tests/ExportInterfaceTest.cs b/tests/ExportInterfaceTest.cs index bacb4b8..49fd9fc 100644 --- a/tests/ExportInterfaceTest.cs +++ b/tests/ExportInterfaceTest.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Threading; using NUnit.Framework; @@ -161,6 +162,41 @@ public void Property () Assert.AreEqual (i + 1, test.SomeProp); } + [Test] + public void AllProperties () + { + var args = string.Format ( + "--dest={0} --type=method_call --print-reply " + + "{1} org.freedesktop.DBus.Properties.GetAll string:{0}", + bus_name, + path + ); + Process dbus = new Process { + StartInfo = new ProcessStartInfo { + FileName = "dbus-send", + Arguments = args, + RedirectStandardOutput = true, + UseShellExecute = false + } + }; + + var iterator = new Thread(() => { do { Bus.Session.Iterate(); } while (true); }); + iterator.Start (); + + if (dbus.Start ()) { + dbus.WaitForExit (); + + string output = dbus.StandardOutput.ReadToEnd (); + Assert.IsNotEmpty (output); + // FIXME: Use a regular expression? + Assert.IsTrue (output.Contains ("SomeProp")); + } else { + Assert.Ignore ("Failed to start test program"); + } + + iterator.Abort (); + } + /// /// ///