public static object[] GetDynamicValues(Message msg, Type[] types) { //TODO: this validation check should provide better information, eg. message dump or a stack trace if (Protocol.Verbose) { if (Signature.GetSig(types) != msg.Signature) { Console.Error.WriteLine("Warning: The signature of the message does not match that of the handler"); } } object[] vals = new object[types.Length]; if (msg.Body != null) { MessageReader reader = new MessageReader(msg); for (int i = 0; i != types.Length; i++) { object arg; reader.GetValue(types[i], out arg); vals[i] = arg; } } return(vals); }
public void SendSignal(MethodInfo mi, string @interface, string member, object[] outValues) { //TODO: make use of bus_name? Type[] outTypes = Mapper.GetTypes(ArgDirection.In, mi.GetParameters()); Signature outSig = Signature.GetSig(outTypes); Signal signal = new Signal(object_path, @interface, member); signal.message.Signature = outSig; if (outValues != null && outValues.Length != 0) { MessageWriter writer = new MessageWriter(Connection.NativeEndianness); writer.connection = conn; for (int i = 0; i != outTypes.Length; i++) { writer.Write(outTypes[i], outValues[i]); } signal.message.Body = writer.ToArray(); } conn.Send(signal.message); }
public void WriteProperty(PropertyInfo pri) { //expose properties as dbus properties writer.WriteStartElement("property"); writer.WriteAttributeString("name", pri.Name); writer.WriteAttributeString("type", Signature.GetSig(pri.PropertyType).Value); string access = (pri.CanRead ? "read" : String.Empty) + (pri.CanWrite ? "write" : String.Empty); writer.WriteAttributeString("access", access); WriteAnnotations(pri); writer.WriteEndElement(); //expose properties as methods also //it may not be worth doing this in the long run /* * if (pri.CanRead) { * writer.WriteStartElement ("method"); * writer.WriteAttributeString ("name", "Get" + pri.Name); * WriteArgReverse (pri.GetGetMethod ().ReturnParameter); * writer.WriteEndElement (); * } * * if (pri.CanWrite) { * writer.WriteStartElement ("method"); * writer.WriteAttributeString ("name", "Set" + pri.Name); * foreach (ParameterInfo pi in pri.GetSetMethod ().GetParameters ()) * WriteArg (pi); * writer.WriteEndElement (); * } */ }
public static object[] GetDynamicValues(Message msg, Type[] types) { //TODO: this validation check should provide better information, eg. message dump or a stack trace, or at least the interface/member if (Protocol.Verbose) { Signature expected = Signature.GetSig(types); Signature actual = msg.Signature; if (actual != expected) { Console.Error.WriteLine("Warning: The signature of the message does not match that of the handler: " + "Expected '" + expected + "', got '" + actual + "'"); } } object[] vals = new object[types.Length]; if (msg.Body != null) { MessageReader reader = new MessageReader(msg); for (int i = 0; i != types.Length; i++) { vals[i] = reader.ReadValue(types[i]); } } return(vals); }
//should generalize this method //it is duplicated in DProxy public static Message ConstructReplyFor(MethodCall method_call, 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.Fields[FieldCode.Destination] = method_call.Sender; } replyMsg.Signature = inSig; //replyMsg.WriteHeader (); return(replyMsg); }
//TODO: merge this with the above method public static Message ConstructReplyFor(MethodCall method_call, Type retType, object retVal) { MethodReturn method_return = new MethodReturn(method_call.message.Header.Serial); Message replyMsg = method_return.message; Signature inSig = Signature.GetSig(retType); if (inSig != Signature.Empty) { MessageWriter writer = new MessageWriter(Connection.NativeEndianness); writer.Write(retType, retVal); 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.Fields[FieldCode.Destination] = method_call.Sender; } replyMsg.Signature = inSig; //replyMsg.WriteHeader (); return(replyMsg); }
//TODO: clean up and get rid of reverse (or argIsOut) parm public void WriteArg (Type argType, string argName, bool argIsOut, bool reverse) { argType = argIsOut ? argType.GetElementType () : argType; if (argType == typeof (void)) return; writer.WriteStartElement ("arg"); if (!String.IsNullOrEmpty (argName)) writer.WriteAttributeString ("name", argName); //we can't rely on the default direction (qt-dbus requires a direction at time of writing), so we use a boolean to reverse the parameter direction and make it explicit if (argIsOut) writer.WriteAttributeString ("direction", !reverse ? "out" : "in"); else writer.WriteAttributeString ("direction", !reverse ? "in" : "out"); Signature sig = Signature.GetSig (argType); //TODO: avoid writing null (DType.Invalid) to the XML stream writer.WriteAttributeString ("type", sig.Value); //annotations aren't valid in an arg element, so this is disabled //if (argType.IsEnum) // WriteAnnotation ("org.ndesk.DBus.Enum", Mapper.GetInterfaceName (argType)); writer.WriteEndElement (); }
public void WriteVariant(Type type, object val) { Signature sig = Signature.GetSig(type); Write(sig); Write(type, val); }
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 ToType(Type conversionType, IFormatProvider provider) { Signature typeSig = Signature.GetSig(conversionType); if (typeSig != signature) { throw new InvalidCastException(String.Format("{0} doesn't match {1}", typeSig.ToString(), signature.ToString())); } MessageReader reader = new MessageReader(endianness, data); return(reader.ReadValue(conversionType)); }
//this is not in the spec, and is not finalized public void WriteEnum (Type type) { writer.WriteStartElement ("enum"); writer.WriteAttributeString ("name", Mapper.GetInterfaceName (type)); writer.WriteAttributeString ("type", Signature.GetSig (type.GetElementType ()).Value); writer.WriteAttributeString ("flags", (type.IsDefined (typeof (FlagsAttribute), false)) ? "true" : "false"); string[] names = Enum.GetNames (type); int i = 0; foreach (Enum val in Enum.GetValues (type)) { writer.WriteStartElement ("element"); writer.WriteAttributeString ("name", names[i++]); writer.WriteAttributeString ("value", val.ToString ("d")); writer.WriteEndElement (); } writer.WriteEndElement (); }
public static bool SigsForMethod(MethodInfo mi, out Signature inSig, out Signature outSig) { inSig = Signature.Empty; outSig = Signature.Empty; foreach (ParameterInfo parm in mi.GetParameters()) { if (parm.IsOut) { outSig += Signature.GetSig(parm.ParameterType.GetElementType()); } else { inSig += Signature.GetSig(parm.ParameterType); } } outSig += Signature.GetSig(mi.ReturnType); return(true); }
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.Fields[FieldCode.Destination] = method_call.Sender; } replyMsg.Signature = outSig; return(replyMsg); }
public bool CanConvertTo(Type conversionType) { Signature typeSig = Signature.GetSig(conversionType); return(signature == typeSig); }
//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); }
public HeaderTest(FieldCode field, object value) { Field = field; Signature = Signature.GetSig(value.GetType()); Value = value; }
public static void GenReadCollection(ILGenerator ilg, Type type) { //Console.WriteLine ("GenReadCollection " + type); //Console.WriteLine ("Sig: " + Signature.GetSig (type)); int fixedSize = 0; if (type.IsArray && Signature.GetSig(type.GetElementType()).GetFixedSize(ref fixedSize)) { GenReadArrayFixed(ilg, type, fixedSize); return; } LocalBuilder readerLocal = ilg.DeclareLocal(typeof(MessageReader)); ilg.Emit(OpCodes.Stloc, readerLocal); //Type[] genArgs = type.GetGenericArguments (); Type[] genArgs = type.IsArray ? new Type[] { type.GetElementType() } : type.GetGenericArguments(); //Type[] genArgs = new Type[] { type.GetElementType () }; //Type tElem = genArgs[0]; //Type collType = Mapper.GetGenericType (typeof (List<>), genArgs); Type collType = Mapper.GetGenericType(genArgs.Length == 2 ? typeof(Dictionary <,>) : typeof(List <>), genArgs); ConstructorInfo ctor = collType.GetConstructor(Type.EmptyTypes); ilg.Emit(OpCodes.Newobj, ctor); LocalBuilder collLocal = ilg.DeclareLocal(collType); ilg.Emit(OpCodes.Stloc, collLocal); //MethodInfo addMethod = dictType.GetMethod ("Add", new Type[] { tKey, tValue }); MethodInfo addMethod = collType.GetMethod("Add", genArgs); // Read the array's byte length MethodInfo readUInt32Method = GetReadMethod(typeof(uint)); ilg.Emit(OpCodes.Ldloc, readerLocal); ilg.Emit(readUInt32Method.IsFinal ? OpCodes.Call : OpCodes.Callvirt, readUInt32Method); { // Align to 8 for structs ilg.Emit(OpCodes.Ldloc, readerLocal); //ilg.Emit (OpCodes.Ldc_I4, 8); // TODO: This padding logic is sketchy ilg.Emit(OpCodes.Ldc_I4, genArgs.Length > 1 ? 8 : Signature.GetSig(genArgs[0]).Alignment); ilg.Emit(OpCodes.Call, messageReaderReadPad); } // Similar to the fixed array loop code FieldInfo posField = typeof(MessageReader).GetField("pos"); LocalBuilder endPosLocal = ilg.DeclareLocal(typeof(int)); ilg.Emit(OpCodes.Ldloc, readerLocal); ilg.Emit(OpCodes.Ldfld, posField); // Add the current position and byte length to determine endPos // TODO: Consider padding? ilg.Emit(OpCodes.Add); ilg.Emit(OpCodes.Stloc, endPosLocal); { Label loopStartLabel = ilg.DefineLabel(); Label loopEndLabel = ilg.DefineLabel(); ilg.Emit(OpCodes.Br, loopEndLabel); ilg.MarkLabel(loopStartLabel); { if (genArgs.Length > 1) { // Align to 8 for structs ilg.Emit(OpCodes.Ldloc, readerLocal); ilg.Emit(OpCodes.Ldc_I4, 8); ilg.Emit(OpCodes.Call, messageReaderReadPad); } // Read and store an element to the array var lbList = new List <LocalBuilder>(); foreach (Type genArg in genArgs) { ilg.Emit(OpCodes.Ldloc, readerLocal); var lb = ilg.DeclareLocal(genArg); lbList.Add(lb); GenReader(ilg, genArg); ilg.Emit(OpCodes.Stloc, lb); } ilg.Emit(OpCodes.Ldloc, collLocal); foreach (var l in lbList) { ilg.Emit(OpCodes.Ldloc, l); } ilg.Emit(OpCodes.Call, addMethod); } ilg.MarkLabel(loopEndLabel); //ilg.Emit (OpCodes.Ldloc, indexLocal); ilg.Emit(OpCodes.Ldloc, readerLocal); ilg.Emit(OpCodes.Ldfld, posField); ilg.Emit(OpCodes.Ldloc, endPosLocal); ilg.Emit(OpCodes.Blt, loopStartLabel); } // Return the new collection ilg.Emit(OpCodes.Ldloc, collLocal); if (type.IsArray) { MethodInfo toArrayMethod = collType.GetMethod("ToArray", Type.EmptyTypes); ilg.Emit(OpCodes.Call, toArrayMethod); } }
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]; MatchRule rule = new MatchRule(); rule.MessageType = MessageType.Signal; rule.Interface = Mapper.GetInterfaceName(mi); rule.Member = ename; rule.Path = object_path; if (parts[0] == "add") { if (conn.Handlers.ContainsKey(rule)) { conn.Handlers[rule] = Delegate.Combine(conn.Handlers[rule], dlg); } else { conn.Handlers[rule] = dlg; conn.AddMatch(rule.ToString()); } } else if (parts[0] == "remove") { conn.Handlers[rule] = Delegate.Remove(conn.Handlers[rule], dlg); if (conn.Handlers[rule] == null) { conn.RemoveMatch(rule.ToString()); conn.Handlers.Remove(rule); } } 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.Fields[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); reader.GetValue(out errMsg); } 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 void GenReadArrayFixed(ILGenerator ilg, Type t, int knownElemSize) { //Console.Error.WriteLine ("GenReadArrayFixed " + t); LocalBuilder readerLocal = ilg.DeclareLocal(typeof(MessageReader)); ilg.Emit(OpCodes.Stloc, readerLocal); Type tElem = t.GetElementType(); Signature sigElem = Signature.GetSig(tElem); int alignElem = sigElem.Alignment; int knownElemSizePadded = Protocol.Padded(knownElemSize, sigElem.Alignment); Type tUnder = tElem.IsEnum ? Enum.GetUnderlyingType(tElem) : tElem; int managedElemSize = System.Runtime.InteropServices.Marshal.SizeOf(tUnder); /* * Console.WriteLine ("managedElemSize: " + managedElemSize); * Console.WriteLine ("elemSize: " + knownElemSize); * Console.WriteLine ("elemSizePadded: " + knownElemSizePadded); */ // Read the array's byte length ilg.Emit(OpCodes.Ldloc, readerLocal); MethodInfo exactMethod = GetReadMethod(typeof(uint)); ilg.Emit(exactMethod.IsFinal ? OpCodes.Call : OpCodes.Callvirt, exactMethod); LocalBuilder sizeLocal = ilg.DeclareLocal(typeof(uint)); ilg.Emit(OpCodes.Stloc, sizeLocal); /* * // Take the array's byte length * ilg.Emit (OpCodes.Ldloc, sizeLocal); * // Divide by the known element size * //ilg.Emit (OpCodes.Ldc_I4, knownElemSizePadded); * ilg.Emit (OpCodes.Ldc_I4, knownElemSize); * ilg.Emit (OpCodes.Div_Un); */ // Create a new array of the correct element length ilg.Emit(OpCodes.Ldloc, sizeLocal); if (knownElemSizePadded > 1) { ilg.Emit(OpCodes.Ldc_I4, alignElem); MethodInfo paddedMethod = typeof(Protocol).GetMethod("Padded"); ilg.Emit(OpCodes.Call, paddedMethod); // Divide by the known element size ilg.Emit(OpCodes.Ldc_I4, knownElemSizePadded); ilg.Emit(OpCodes.Div_Un); } ilg.Emit(OpCodes.Newarr, tElem); LocalBuilder aryLocal = ilg.DeclareLocal(t); ilg.Emit(OpCodes.Stloc, aryLocal); Label nonBlitLabel = ilg.DefineLabel(); Label endLabel = ilg.DefineLabel(); // Skip read or blit for zero-length arrays. ilg.Emit(OpCodes.Ldloc, sizeLocal); ilg.Emit(OpCodes.Brfalse, endLabel); // WARNING: This may skew pos when we later increment it! if (alignElem > 4) { // Align to element if alignment requirement is higher than 4 (since we just read a uint) ilg.Emit(OpCodes.Ldloc, readerLocal); ilg.Emit(OpCodes.Ldc_I4, alignElem); ilg.Emit(OpCodes.Call, messageReaderReadPad); } // Blit where possible // shouldBlit: Blit if endian is native // mustBlit: Blit regardless of endian (ie. byte or structs containing only bytes) bool shouldBlit = tElem.IsValueType && knownElemSizePadded == managedElemSize && !sigElem.IsStruct; //bool shouldBlit = tElem.IsValueType && knownElemSizePadded == managedElemSize; // bool and char are not reliably blittable, so we don't allow blitting in these cases. // Their exact layout varies between runtimes, platforms and even data types. shouldBlit &= tElem != typeof(bool) && tElem != typeof(char); bool mustBlit = shouldBlit && knownElemSizePadded == 1; if (shouldBlit) { //Console.Error.WriteLine ("Blit read array " + tElem); if (!mustBlit) { // Check to see if we can blit the data structures FieldInfo nativeEndianField = typeof(MessageReader).GetField("IsNativeEndian"); ilg.Emit(OpCodes.Ldloc, readerLocal); ilg.Emit(OpCodes.Ldfld, nativeEndianField); ilg.Emit(OpCodes.Brfalse_S, nonBlitLabel); } // Get the destination address ilg.Emit(OpCodes.Ldloc, aryLocal); ilg.Emit(OpCodes.Ldc_I4_0); ilg.Emit(OpCodes.Ldelema, tElem); // Get the source address FieldInfo dataField = typeof(MessageReader).GetField("data"); FieldInfo posField = typeof(MessageReader).GetField("pos"); ilg.Emit(OpCodes.Ldloc, readerLocal); ilg.Emit(OpCodes.Ldfld, dataField); { ilg.Emit(OpCodes.Ldloc, readerLocal); ilg.Emit(OpCodes.Ldfld, posField); } ilg.Emit(OpCodes.Ldelema, typeof(byte)); // The number of bytes to copy ilg.Emit(OpCodes.Ldloc, sizeLocal); // Blit the array ilg.Emit(OpCodes.Cpblk); // pos += bytesRead ilg.Emit(OpCodes.Ldloc, readerLocal); ilg.Emit(OpCodes.Ldloc, readerLocal); ilg.Emit(OpCodes.Ldfld, posField); ilg.Emit(OpCodes.Ldloc, sizeLocal); ilg.Emit(OpCodes.Add); ilg.Emit(OpCodes.Stfld, posField); ilg.Emit(OpCodes.Br, endLabel); } if (!mustBlit) { ilg.MarkLabel(nonBlitLabel); // for (int i = 0 ; i < ary.Length ; i++) LocalBuilder indexLocal = ilg.DeclareLocal(typeof(int)); ilg.Emit(OpCodes.Ldc_I4_0); ilg.Emit(OpCodes.Stloc, indexLocal); Label loopStartLabel = ilg.DefineLabel(); Label loopEndLabel = ilg.DefineLabel(); ilg.Emit(OpCodes.Br, loopEndLabel); ilg.MarkLabel(loopStartLabel); { // Read and store an element to the array ilg.Emit(OpCodes.Ldloc, aryLocal); ilg.Emit(OpCodes.Ldloc, indexLocal); ilg.Emit(OpCodes.Ldloc, readerLocal); GenReader(ilg, tElem); ilg.Emit(OpCodes.Stelem, tElem); } // i++ ilg.Emit(OpCodes.Ldloc, indexLocal); ilg.Emit(OpCodes.Ldc_I4_1); ilg.Emit(OpCodes.Add); ilg.Emit(OpCodes.Stloc, indexLocal); ilg.MarkLabel(loopEndLabel); ilg.Emit(OpCodes.Ldloc, indexLocal); ilg.Emit(OpCodes.Ldloc, aryLocal); ilg.Emit(OpCodes.Ldlen); ilg.Emit(OpCodes.Blt, loopStartLabel); } ilg.MarkLabel(endLabel); // Return the new array ilg.Emit(OpCodes.Ldloc, aryLocal); }
public object SendMethodCall(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.Fields[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 static void GenHookupMethod(ILGenerator ilg, MethodInfo declMethod, MethodInfo invokeMethod, string @interface, string member) { ParameterInfo[] parms = declMethod.GetParameters(); Type retType = declMethod.ReturnType; //the BusObject instance ilg.Emit(OpCodes.Ldarg_0); //MethodInfo /* * ilg.Emit (OpCodes.Ldtoken, declMethod); * ilg.Emit (OpCodes.Call, getMethodFromHandleMethod); */ //interface ilg.Emit(OpCodes.Ldstr, @interface); //special case event add/remove methods if (declMethod.IsSpecialName && (declMethod.Name.StartsWith("add_") || declMethod.Name.StartsWith("remove_"))) { string[] parts = declMethod.Name.Split(new char[] { '_' }, 2); string ename = parts[1]; //Delegate dlg = (Delegate)inArgs[0]; bool adding = parts[0] == "add"; ilg.Emit(OpCodes.Ldstr, ename); ilg.Emit(OpCodes.Ldarg_1); ilg.Emit(OpCodes.Ldc_I4, adding ? 1 : 0); ilg.Emit(OpCodes.Tailcall); ilg.Emit(toggleSignalMethod.IsFinal ? OpCodes.Call : OpCodes.Callvirt, toggleSignalMethod); ilg.Emit(OpCodes.Ret); return; } //property accessor mapping if (declMethod.IsSpecialName) { if (member.StartsWith("get_")) { member = "Get" + member.Substring(4); } else if (member.StartsWith("set_")) { member = "Set" + member.Substring(4); } } //member ilg.Emit(OpCodes.Ldstr, member); //signature Signature inSig = Signature.Empty; Signature outSig = Signature.Empty; if (!declMethod.IsSpecialName) { foreach (ParameterInfo parm in parms) { if (parm.IsOut) { outSig += Signature.GetSig(parm.ParameterType.GetElementType()); } else { inSig += Signature.GetSig(parm.ParameterType); } } } ilg.Emit(OpCodes.Ldstr, inSig.Value); LocalBuilder writer = ilg.DeclareLocal(typeof(MessageWriter)); ilg.Emit(OpCodes.Newobj, messageWriterConstructor); ilg.Emit(OpCodes.Stloc, writer); foreach (ParameterInfo parm in parms) { if (parm.IsOut) { continue; } Type t = parm.ParameterType; //offset by one to account for "this" int i = parm.Position + 1; //null checking of parameters (but not their recursive contents) if (!t.IsValueType) { Label notNull = ilg.DefineLabel(); //if the value is null... ilg.Emit(OpCodes.Ldarg, i); ilg.Emit(OpCodes.Brtrue_S, notNull); //...throw Exception string paramName = parm.Name; ilg.Emit(OpCodes.Ldstr, paramName); ilg.Emit(OpCodes.Newobj, argumentNullExceptionConstructor); ilg.Emit(OpCodes.Throw); //was not null, so all is well ilg.MarkLabel(notNull); } ilg.Emit(OpCodes.Ldloc, writer); //the parameter ilg.Emit(OpCodes.Ldarg, i); GenWriter(ilg, t); } ilg.Emit(OpCodes.Ldloc, writer); //the expected return Type ilg.Emit(OpCodes.Ldtoken, retType); ilg.Emit(OpCodes.Call, getTypeFromHandleMethod); LocalBuilder exc = ilg.DeclareLocal(typeof(Exception)); ilg.Emit(OpCodes.Ldloca_S, exc); //make the call ilg.Emit(invokeMethod.IsFinal ? OpCodes.Call : OpCodes.Callvirt, invokeMethod); //define a label we'll use to deal with a non-null Exception Label noErr = ilg.DefineLabel(); //if the out Exception is not null... ilg.Emit(OpCodes.Ldloc, exc); ilg.Emit(OpCodes.Brfalse_S, noErr); //...throw it. ilg.Emit(OpCodes.Ldloc, exc); ilg.Emit(OpCodes.Throw); //Exception was null, so all is well ilg.MarkLabel(noErr); if (retType == typeof(void)) { //we aren't expecting a return value, so throw away the (hopefully) null return if (invokeMethod.ReturnType != typeof(void)) { ilg.Emit(OpCodes.Pop); } } else { if (retType.IsValueType) { ilg.Emit(OpCodes.Unbox_Any, retType); } else { ilg.Emit(OpCodes.Castclass, retType); } } ilg.Emit(OpCodes.Ret); }
//this requires a seekable stream for now public unsafe void WriteArray <T> (T[] val) { Type elemType = typeof(T); if (elemType == typeof(byte)) { if (val.Length > Protocol.MaxArrayLength) { throw new Exception("Array length " + val.Length + " exceeds maximum allowed " + Protocol.MaxArrayLength + " bytes"); } Write((uint)val.Length); stream.Write((byte[])(object)val, 0, val.Length); return; } if (elemType.IsEnum) { elemType = Enum.GetUnderlyingType(elemType); } Signature sigElem = Signature.GetSig(elemType); int fixedSize = 0; if (endianness == Connection.NativeEndianness && elemType.IsValueType && !sigElem.IsStruct && sigElem.GetFixedSize(ref fixedSize)) { int byteLength = fixedSize * val.Length; if (byteLength > Protocol.MaxArrayLength) { throw new Exception("Array length " + byteLength + " exceeds maximum allowed " + Protocol.MaxArrayLength + " bytes"); } Write((uint)byteLength); WritePad(sigElem.Alignment); GCHandle valHandle = GCHandle.Alloc(val, GCHandleType.Pinned); IntPtr p = valHandle.AddrOfPinnedObject(); byte[] data = new byte[byteLength]; byte * bp = (byte *)p; for (int i = 0; i != byteLength; i++) { data[i] = bp[i]; } stream.Write(data, 0, data.Length); valHandle.Free(); return; } long origPos = stream.Position; Write((uint)0); //advance to the alignment of the element WritePad(sigElem.Alignment); long startPos = stream.Position; TypeWriter <T> tWriter = TypeImplementer.GetTypeWriter <T> (); foreach (T elem in val) { tWriter(this, elem); } long endPos = stream.Position; uint ln = (uint)(endPos - startPos); stream.Position = origPos; if (ln > Protocol.MaxArrayLength) { throw new Exception("Array length " + ln + " exceeds maximum allowed " + Protocol.MaxArrayLength + " bytes"); } Write(ln); stream.Position = endPos; }
public static string GetSignatureString(Type type) { return(Signature.GetSig(type).Value); }