2 // System.Runtime.Remoting.Messaging.CADMessages.cs
7 // (C) Patrik Torstensson
11 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
13 // Permission is hereby granted, free of charge, to any person obtaining
14 // a copy of this software and associated documentation files (the
15 // "Software"), to deal in the Software without restriction, including
16 // without limitation the rights to use, copy, modify, merge, publish,
17 // distribute, sublicense, and/or sell copies of the Software, and to
18 // permit persons to whom the Software is furnished to do so, subject to
19 // the following conditions:
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 using System.Collections;
36 using System.Reflection;
37 using System.Runtime.Serialization;
38 using System.Runtime.Remoting;
39 using System.Runtime.Remoting.Channels;
40 using System.Runtime.Remoting.Messaging;
41 using System.Runtime.Remoting.Proxies;
43 namespace System.Runtime.Remoting.Messaging {
45 internal class CADArgHolder {
48 public CADArgHolder (int i) {
53 internal class CADObjRef {
54 internal ObjRef objref;
55 internal int SourceDomain;
56 internal byte[] TypeInfo;
58 public CADObjRef (ObjRef o, int sourceDomain) {
60 TypeInfo = o.SerializeType ();
61 SourceDomain = sourceDomain;
64 public string TypeName {
65 get { return objref.TypeInfo.TypeName; }
69 get { return objref.URI; }
74 internal class CADMethodRef
76 internal string FullTypeName;
77 internal IntPtr MethodHandlePtr;
79 public RuntimeMethodHandle MethodHandle {
81 return new RuntimeMethodHandle (MethodHandlePtr);
85 public CADMethodRef (IMethodMessage msg)
87 MethodHandlePtr = msg.MethodBase.MethodHandle.Value;
88 FullTypeName = msg.MethodBase.DeclaringType.AssemblyQualifiedName;
92 internal class CADMessageBase {
94 protected object [] _args;
95 protected byte [] _serializedArgs = null;
96 protected int _propertyCount = 0;
97 protected CADArgHolder _callContext;
98 internal byte[] serializedMethod;
100 public CADMessageBase (IMethodMessage msg) {
101 CADMethodRef methodRef = new CADMethodRef (msg);
102 serializedMethod = CADSerializer.SerializeObject (methodRef).GetBuffer ();
105 internal MethodBase method {
106 get { return GetMethod (); }
109 internal MethodBase GetMethod ()
111 CADMethodRef methRef = (CADMethodRef)CADSerializer.DeserializeObjectSafe (serializedMethod);
115 Type tt = Type.GetType (methRef.FullTypeName, true);
116 if (tt.IsGenericType || tt.IsGenericTypeDefinition) {
117 _method = MethodBase.GetMethodFromHandleNoGenericCheck (methRef.MethodHandle);
119 _method = MethodBase.GetMethodFromHandle (methRef.MethodHandle);
122 if (tt != _method.DeclaringType) {
123 // The target domain has loaded the type from a different assembly.
124 // We need to locate the correct type and get the method from it
125 Type [] signature = GetSignature (_method, true);
126 if (_method.IsGenericMethod) {
127 MethodBase [] methods = tt.GetMethods (BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Instance);
128 Type [] base_args = _method.GetGenericArguments ();
129 foreach (MethodBase method in methods) {
130 if (!method.IsGenericMethod || method.Name != _method.Name)
132 Type [] method_args = method.GetGenericArguments ();
133 if (base_args.Length != method_args.Length)
136 MethodInfo method_instance = ((MethodInfo) method).MakeGenericMethod (base_args);
137 Type [] base_sig = GetSignature (method_instance, false);
138 if (base_sig.Length != signature.Length) {
142 for (int i = base_sig.Length - 1; i >= 0; i--) {
143 if (base_sig [i] != signature [i]) {
150 return method_instance;
155 MethodBase mb = tt.GetMethod (_method.Name, BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Instance, null, signature, null);
157 throw new RemotingException ("Method '" + _method.Name + "' not found in type '" + tt + "'");
163 static protected Type [] GetSignature (MethodBase methodBase, bool load)
165 ParameterInfo[] pars = methodBase.GetParameters ();
166 Type[] signature = new Type [pars.Length];
167 for (int n=0; n<pars.Length; n++) {
168 // The parameter types may also be loaded from a different assembly, so we need
169 // to load them again
171 signature [n] = Type.GetType (pars [n].ParameterType.AssemblyQualifiedName, true);
173 signature [n] = pars [n].ParameterType;
177 // Helper to marshal properties
178 internal static int MarshalProperties (IDictionary dict, ref ArrayList args) {
179 IDictionary serDict = dict;
182 MessageDictionary msgDict = dict as MessageDictionary;
183 if (null != msgDict) {
184 if (msgDict.HasUserData ()) {
185 serDict = msgDict.InternalDictionary;
186 if (null != serDict) {
187 foreach (DictionaryEntry e in serDict) {
189 args = new ArrayList();
197 foreach (DictionaryEntry e in serDict) {
199 args = new ArrayList();
209 internal static void UnmarshalProperties (IDictionary dict, int count, ArrayList args) {
210 for (int i = 0; i < count; i++) {
211 DictionaryEntry e = (DictionaryEntry) args [i];
212 dict [e.Key] = e.Value;
216 // We can ignore marshalling for string and primitive types
217 private static bool IsPossibleToIgnoreMarshal (object obj) {
219 Type objType = obj.GetType();
220 if (objType.IsPrimitive || objType == typeof(void))
223 if (objType.IsArray && objType.GetElementType().IsPrimitive && ((Array)obj).Rank == 1)
226 if (obj is string || obj is DateTime || obj is TimeSpan)
232 // Checks an argument if it's possible to pass without marshalling and
233 // if not it will be added to arguments to be serialized
234 protected object MarshalArgument (object arg, ref ArrayList args) {
238 if (IsPossibleToIgnoreMarshal (arg))
241 MarshalByRefObject mbr = arg as MarshalByRefObject;
244 if (RemotingServices.IsTransparentProxy(mbr)) {
245 // We don't deal with this case yet
248 ObjRef objRef = RemotingServices.Marshal(mbr);
249 return new CADObjRef(objRef, System.Threading.Thread.GetDomainID());
254 args = new ArrayList();
258 // return position that the arg exists in the serialized list
259 return new CADArgHolder(args.Count - 1);
262 protected object UnmarshalArgument (object arg, ArrayList args) {
263 if (arg == null) return null;
265 // Check if argument is an holder (then we know that it's a serialized argument)
266 CADArgHolder holder = arg as CADArgHolder;
267 if (null != holder) {
268 return args [holder.index];
271 CADObjRef objref = arg as CADObjRef;
272 if (null != objref) {
273 ObjRef localRef = objref.objref.DeserializeInTheCurrentDomain (objref.SourceDomain, objref.TypeInfo);
274 return RemotingServices.Unmarshal (localRef);
279 Array argb = (Array)arg;
282 // We can't use Array.CreateInstance (arg.GetType().GetElementType()) because
283 // GetElementType() returns a type from the source domain.
285 switch (Type.GetTypeCode (arg.GetType().GetElementType()))
287 case TypeCode.Boolean: argn = new bool [argb.Length]; break;
288 case TypeCode.Byte: argn = new Byte [argb.Length]; break;
289 case TypeCode.Char: argn = new Char [argb.Length]; break;
290 case TypeCode.Decimal: argn = new Decimal [argb.Length]; break;
291 case TypeCode.Double: argn = new Double [argb.Length]; break;
292 case TypeCode.Int16: argn = new Int16 [argb.Length]; break;
293 case TypeCode.Int32: argn = new Int32 [argb.Length]; break;
294 case TypeCode.Int64: argn = new Int64 [argb.Length]; break;
295 case TypeCode.SByte: argn = new SByte [argb.Length]; break;
296 case TypeCode.Single: argn = new Single [argb.Length]; break;
297 case TypeCode.UInt16: argn = new UInt16 [argb.Length]; break;
298 case TypeCode.UInt32: argn = new UInt32 [argb.Length]; break;
299 case TypeCode.UInt64: argn = new UInt64 [argb.Length]; break;
300 default: throw new NotSupportedException ();
303 argb.CopyTo (argn, 0);
307 switch (Type.GetTypeCode (arg.GetType()))
309 case TypeCode.Boolean: return (bool)arg;
310 case TypeCode.Byte: return (byte)arg;
311 case TypeCode.Char: return (char)arg;
312 case TypeCode.Decimal: return (decimal)arg;
313 case TypeCode.Double: return (double)arg;
314 case TypeCode.Int16: return (Int16)arg;
315 case TypeCode.Int32: return (Int32)arg;
316 case TypeCode.Int64: return (Int64)arg;
317 case TypeCode.SByte: return (SByte)arg;
318 case TypeCode.Single: return (Single)arg;
319 case TypeCode.UInt16: return (UInt16)arg;
320 case TypeCode.UInt32: return (UInt32)arg;
321 case TypeCode.UInt64: return (UInt64)arg;
322 case TypeCode.String: return string.Copy ((string) arg);
323 case TypeCode.DateTime: return new DateTime (((DateTime)arg).Ticks);
325 if (arg is TimeSpan) return new TimeSpan (((TimeSpan)arg).Ticks);
326 if (arg is IntPtr) return (IntPtr) arg;
330 throw new NotSupportedException ("Parameter of type " + arg.GetType () + " cannot be unmarshalled");
333 internal object [] MarshalArguments (object [] arguments, ref ArrayList args) {
334 object [] marshalledArgs = new object [arguments.Length];
336 int total = arguments.Length;
337 for (int i = 0; i < total; i++)
338 marshalledArgs [i] = MarshalArgument (arguments [i], ref args);
340 return marshalledArgs;
343 internal object [] UnmarshalArguments (object [] arguments, ArrayList args) {
344 object [] unmarshalledArgs = new object [arguments.Length];
346 int total = arguments.Length;
347 for (int i = 0; i < total; i++)
348 unmarshalledArgs [i] = UnmarshalArgument (arguments [i], args);
350 return unmarshalledArgs;
353 protected void SaveLogicalCallContext (IMethodMessage msg, ref ArrayList serializeList)
355 if (msg.LogicalCallContext != null && msg.LogicalCallContext.HasInfo)
357 if (serializeList == null)
358 serializeList = new ArrayList();
360 _callContext = new CADArgHolder (serializeList.Count);
361 serializeList.Add (msg.LogicalCallContext);
365 internal LogicalCallContext GetLogicalCallContext (ArrayList args)
367 if (null == _callContext)
370 return (LogicalCallContext) args [_callContext.index];
374 // Used when passing a IMethodCallMessage between appdomains
375 internal class CADMethodCallMessage : CADMessageBase {
378 internal string Uri {
384 static internal CADMethodCallMessage Create (IMessage callMsg) {
385 IMethodCallMessage msg = callMsg as IMethodCallMessage;
389 return new CADMethodCallMessage (msg);
392 internal CADMethodCallMessage (IMethodCallMessage callMsg): base (callMsg) {
395 ArrayList serializeList = null;
397 _propertyCount = MarshalProperties (callMsg.Properties, ref serializeList);
399 _args = MarshalArguments ( callMsg.Args, ref serializeList);
402 SaveLogicalCallContext (callMsg, ref serializeList);
404 // Serialize message data if needed
406 if (null != serializeList) {
407 MemoryStream stm = CADSerializer.SerializeObject (serializeList.ToArray());
408 _serializedArgs = stm.GetBuffer();
412 internal ArrayList GetArguments () {
413 ArrayList ret = null;
415 if (null != _serializedArgs) {
416 object[] oret = (object[]) CADSerializer.DeserializeObject (new MemoryStream (_serializedArgs));
417 ret = new ArrayList (oret);
418 _serializedArgs = null;
424 internal object [] GetArgs (ArrayList args) {
425 return UnmarshalArguments (_args, args);
428 internal int PropertiesCount {
430 return _propertyCount;
436 // Used when passing a IMethodReturnMessage between appdomains
437 internal class CADMethodReturnMessage : CADMessageBase {
439 CADArgHolder _exception = null;
440 #pragma warning disable 414
442 #pragma warning restore
444 static internal CADMethodReturnMessage Create (IMessage callMsg) {
445 IMethodReturnMessage msg = callMsg as IMethodReturnMessage;
449 return new CADMethodReturnMessage (msg);
452 internal CADMethodReturnMessage(IMethodReturnMessage retMsg): base (retMsg) {
453 ArrayList serializeList = null;
455 _propertyCount = MarshalProperties (retMsg.Properties, ref serializeList);
457 _returnValue = MarshalArgument ( retMsg.ReturnValue, ref serializeList);
458 _args = MarshalArguments ( retMsg.Args, ref serializeList);
460 _sig = GetSignature (method, true);
462 if (null != retMsg.Exception) {
463 if (null == serializeList)
464 serializeList = new ArrayList();
466 _exception = new CADArgHolder (serializeList.Count);
467 serializeList.Add(retMsg.Exception);
471 SaveLogicalCallContext (retMsg, ref serializeList);
473 if (null != serializeList) {
474 MemoryStream stm = CADSerializer.SerializeObject (serializeList.ToArray());
475 _serializedArgs = stm.GetBuffer();
479 internal ArrayList GetArguments () {
480 ArrayList ret = null;
482 if (null != _serializedArgs) {
483 object[] oret = (object[]) CADSerializer.DeserializeObject (new MemoryStream (_serializedArgs));
484 ret = new ArrayList (oret);
485 _serializedArgs = null;
491 internal object [] GetArgs (ArrayList args) {
492 return UnmarshalArguments (_args, args);
495 internal object GetReturnValue (ArrayList args) {
496 return UnmarshalArgument (_returnValue, args);
499 internal Exception GetException(ArrayList args) {
500 if (null == _exception)
503 return (Exception) args [_exception.index];
506 internal int PropertiesCount {
508 return _propertyCount;