public override void HandleMethodCall(MethodCall method_call) { //object retVal = obj.GetType ().InvokeMember (method_call.Member, BindingFlags.InvokeMethod, null, obj, new object[0]); //IDynamicMetaObjectProvider idyn = obj as IDynamicMetaObjectProvider; object retVal = null; Exception raisedException = null; try { object[] args = MessageHelper.GetDynamicValues (method_call.message); retVal = ops.InvokeMember (obj, method_call.Member, args); //retVal = ops.Call (ops.GetMember (obj, method_call.Member), args); } catch (Exception e) { raisedException = e; } if (!method_call.message.ReplyExpected) return; Message msg = method_call.message; Message replyMsg = null; if (raisedException == null) { MethodReturn method_return = new MethodReturn (msg.Header.Serial); replyMsg = method_return.message; if (retVal != null) { if (retVal.GetType ().FullName == "IronRuby.Builtins.MutableString") retVal = retVal.ToString (); // TODO: Invalid sig handling Signature outSig = Signature.GetSig (retVal.GetType ()); MessageWriter retWriter = new MessageWriter (); retWriter.Write (retVal.GetType (), retVal); //retWriter.WriteValueType (retVal, retVal.GetType ()); replyMsg.Body = retWriter.ToArray (); replyMsg.Signature = outSig; } } else { Error error = method_call.CreateError (Mapper.GetInterfaceName (raisedException.GetType ()), raisedException.Message); replyMsg = error.message; } if (method_call.Sender != null) replyMsg.Header[FieldCode.Destination] = method_call.Sender; conn.Send (replyMsg); }
public object SendMethodCallOld(string iface, string member, string inSigStr, MessageWriter writer, Type retType, out Exception exception) { exception = null; //TODO: don't ignore retVal, exception etc. Signature inSig = String.IsNullOrEmpty (inSigStr) ? Signature.Empty : new Signature (inSigStr); MethodCall method_call = new MethodCall (object_path, iface, member, bus_name, inSig); Message callMsg = method_call.message; callMsg.Body = writer.ToArray (); //Invoke Code:: //TODO: complete out parameter support /* Type[] outParmTypes = Mapper.GetTypes (ArgDirection.Out, mi.GetParameters ()); Signature outParmSig = Signature.GetSig (outParmTypes); if (outParmSig != Signature.Empty) throw new Exception ("Out parameters not yet supported: out_signature='" + outParmSig.Value + "'"); */ Type[] outTypes = new Type[1]; outTypes[0] = retType; //we default to always requiring replies for now, even though unnecessary //this is to make sure errors are handled synchronously //TODO: don't hard code this bool needsReply = true; //if (mi.ReturnType == typeof (void)) // needsReply = false; callMsg.ReplyExpected = needsReply; callMsg.Signature = inSig; if (!needsReply) { conn.Send (callMsg); return null; } #if PROTO_REPLY_SIGNATURE if (needsReply) { Signature outSig = Signature.GetSig (outTypes); callMsg.Header[FieldCode.ReplySignature] = outSig; } #endif Message retMsg = conn.SendWithReplyAndBlock (callMsg); object retVal = null; //handle the reply message switch (retMsg.Header.MessageType) { case MessageType.MethodReturn: object[] retVals = MessageHelper.GetDynamicValues (retMsg, outTypes); if (retVals.Length != 0) retVal = retVals[retVals.Length - 1]; break; case MessageType.Error: //TODO: typed exceptions Error error = new Error (retMsg); string errMsg = String.Empty; if (retMsg.Signature.Value.StartsWith ("s")) { MessageReader reader = new MessageReader (retMsg); errMsg = reader.ReadString (); } exception = new Exception (error.ErrorName + ": " + errMsg); break; default: throw new Exception ("Got unexpected message of type " + retMsg.Header.MessageType + " while waiting for a MethodReturn or Error"); } return retVal; }
public void Invoke(MethodBase methodBase, string methodName, object[] inArgs, out object[] outArgs, out object retVal, out Exception exception) { outArgs = new object[0]; retVal = null; exception = null; MethodInfo mi = methodBase as MethodInfo; if (mi != null && mi.IsSpecialName && (methodName.StartsWith ("add_") || methodName.StartsWith ("remove_"))) { string[] parts = methodName.Split (new char[]{'_'}, 2); string ename = parts[1]; Delegate dlg = (Delegate)inArgs[0]; ToggleSignal (Mapper.GetInterfaceName (mi), ename, dlg, parts[0] == "add"); return; } Type[] inTypes = Mapper.GetTypes (ArgDirection.In, mi.GetParameters ()); Signature inSig = Signature.GetSig (inTypes); MethodCall method_call; Message callMsg; //build the outbound method call message { //this bit is error-prone (no null checking) and will need rewriting when DProxy is replaced string iface = null; if (mi != null) iface = Mapper.GetInterfaceName (mi); //map property accessors //TODO: this needs to be done properly, not with simple String.Replace //note that IsSpecialName is also for event accessors, but we already handled those and returned if (mi != null && mi.IsSpecialName) { methodName = methodName.Replace ("get_", "Get"); methodName = methodName.Replace ("set_", "Set"); } method_call = new MethodCall (object_path, iface, methodName, bus_name, inSig); callMsg = method_call.message; if (inArgs != null && inArgs.Length != 0) { MessageWriter writer = new MessageWriter (Connection.NativeEndianness); writer.connection = conn; for (int i = 0 ; i != inTypes.Length ; i++) writer.Write (inTypes[i], inArgs[i]); callMsg.Body = writer.ToArray (); } } //TODO: complete out parameter support /* Type[] outParmTypes = Mapper.GetTypes (ArgDirection.Out, mi.GetParameters ()); Signature outParmSig = Signature.GetSig (outParmTypes); if (outParmSig != Signature.Empty) throw new Exception ("Out parameters not yet supported: out_signature='" + outParmSig.Value + "'"); */ Type[] outTypes = new Type[1]; outTypes[0] = mi.ReturnType; //we default to always requiring replies for now, even though unnecessary //this is to make sure errors are handled synchronously //TODO: don't hard code this bool needsReply = true; //if (mi.ReturnType == typeof (void)) // needsReply = false; callMsg.ReplyExpected = needsReply; callMsg.Signature = inSig; if (!needsReply) { conn.Send (callMsg); return; } #if PROTO_REPLY_SIGNATURE if (needsReply) { Signature outSig = Signature.GetSig (outTypes); callMsg.Header[FieldCode.ReplySignature] = outSig; } #endif Message retMsg = conn.SendWithReplyAndBlock (callMsg); //handle the reply message switch (retMsg.Header.MessageType) { case MessageType.MethodReturn: object[] retVals = MessageHelper.GetDynamicValues (retMsg, outTypes); if (retVals.Length != 0) retVal = retVals[retVals.Length - 1]; break; case MessageType.Error: //TODO: typed exceptions Error error = new Error (retMsg); string errMsg = String.Empty; if (retMsg.Signature.Value.StartsWith ("s")) { MessageReader reader = new MessageReader (retMsg); errMsg = reader.ReadString (); } exception = new Exception (error.ErrorName + ": " + errMsg); break; default: throw new Exception ("Got unexpected message of type " + retMsg.Header.MessageType + " while waiting for a MethodReturn or Error"); } return; }
public static Message CreateUnknownMethodError(MethodCall method_call) { if (!method_call.message.ReplyExpected) return null; string errMsg = String.Format ("Method \"{0}\" with signature \"{1}\" on interface \"{2}\" doesn't exist", method_call.Member, method_call.Signature.Value, method_call.Interface); Error error = new Error ("org.freedesktop.DBus.Error.UnknownMethod", method_call.message.Header.Serial); error.message.Signature = Signature.StringSig; MessageWriter writer = new MessageWriter (Connection.NativeEndianness); writer.Write (errMsg); error.message.Body = writer.ToArray (); //TODO: we should be more strict here, but this fallback was added as a quick fix for p2p if (method_call.Sender != null) error.message.Header[FieldCode.Destination] = method_call.Sender; return error.message; }
public static Message ConstructReply(MethodCall method_call, params object[] vals) { MethodReturn method_return = new MethodReturn (method_call.message.Header.Serial); Message replyMsg = method_return.message; Signature inSig = Signature.GetSig (vals); if (vals != null && vals.Length != 0) { MessageWriter writer = new MessageWriter (Connection.NativeEndianness); foreach (object arg in vals) writer.Write (arg.GetType (), arg); replyMsg.Body = writer.ToArray (); } //TODO: we should be more strict here, but this fallback was added as a quick fix for p2p if (method_call.Sender != null) replyMsg.Header[FieldCode.Destination] = method_call.Sender; replyMsg.Signature = inSig; //replyMsg.WriteHeader (); return replyMsg; }
public static Message ConstructDynamicReply(MethodCall method_call, MethodInfo mi, object retVal, object[] vals) { Type retType = mi.ReturnType; MethodReturn method_return = new MethodReturn (method_call.message.Header.Serial); Message replyMsg = method_return.message; Signature outSig = Signature.GetSig (retType); outSig += Signature.GetSig (Mapper.GetTypes (ArgDirection.Out, mi.GetParameters ())); if (outSig != Signature.Empty) { MessageWriter writer = new MessageWriter (Connection.NativeEndianness); //first write the return value, if any if (retType != null && retType != typeof (void)) writer.Write (retType, retVal); //then write the out args WriteDynamicValues (writer, mi.GetParameters (), vals); replyMsg.Body = writer.ToArray (); } //TODO: we should be more strict here, but this fallback was added as a quick fix for p2p if (method_call.Sender != null) replyMsg.Header[FieldCode.Destination] = method_call.Sender; replyMsg.Signature = outSig; return replyMsg; }
//this method walks the interface tree in an undefined manner and returns the first match, or if no matches are found, null //the logic needs review and cleanup //TODO: unify member name mapping as is already done with interfaces and args public static MethodInfo GetMethod(Type type, MethodCall method_call) { foreach (MemberInfo member in Mapper.GetPublicMembers (type)) { //this could be made more efficient by using the given interface name earlier and avoiding walking through all public interfaces if (method_call.Interface != null) if (GetInterfaceName (member) != method_call.Interface) continue; MethodInfo meth = null; Type[] inTypes = null; if (member is PropertyInfo) { PropertyInfo prop = member as PropertyInfo; MethodInfo getter = prop.GetGetMethod (false); MethodInfo setter = prop.GetSetMethod (false); if (getter != null && "Get" + prop.Name == method_call.Member) { meth = getter; inTypes = Type.EmptyTypes; } else if (setter != null && "Set" + prop.Name == method_call.Member) { meth = setter; inTypes = new Type[] {prop.PropertyType}; } } else { meth = member as MethodInfo; if (meth == null) continue; if (meth.Name != method_call.Member) continue; inTypes = Mapper.GetTypes (ArgDirection.In, meth.GetParameters ()); } if (meth == null || inTypes == null) continue; Signature inSig = Signature.GetSig (inTypes); if (inSig != method_call.Signature) continue; return meth; } return null; }