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
{
55 public int SourceDomain
;
57 public CADObjRef (ObjRef o
, int sourceDomain
) {
59 SourceDomain
= sourceDomain
;
62 public string TypeName
{
63 get { return objref.TypeInfo.TypeName; }
67 get { return objref.URI; }
71 internal class CADMessageBase
{
73 protected object [] _args
;
74 protected byte [] _serializedArgs
= null;
75 protected int _propertyCount
= 0;
76 protected CADArgHolder _callContext
;
78 // Helper to marshal properties
79 internal static int MarshalProperties (IDictionary dict
, ref ArrayList args
) {
80 IDictionary serDict
= dict
;
83 MethodDictionary msgDict
= dict
as MethodDictionary
;
84 if (null != msgDict
) {
85 if (msgDict
.HasInternalProperties
) {
86 serDict
= msgDict
.InternalProperties
;
87 if (null != serDict
) {
88 foreach (DictionaryEntry e
in serDict
) {
90 args
= new ArrayList();
98 foreach (DictionaryEntry e
in serDict
) {
100 args
= new ArrayList();
110 internal static void UnmarshalProperties (IDictionary dict
, int count
, ArrayList args
) {
111 for (int i
= 0; i
< count
; i
++) {
112 DictionaryEntry e
= (DictionaryEntry
) args
[i
];
113 dict
[e
.Key
] = e
.Value
;
117 // We can ignore marshalling for string and primitive types
118 private static bool IsPossibleToIgnoreMarshal (object obj
) {
120 Type objType
= obj
.GetType();
121 if (objType
.IsPrimitive
|| objType
== typeof(void))
124 if (objType
.IsArray
&& objType
.GetElementType().IsPrimitive
&& ((Array
)obj
).Rank
== 1)
127 if (obj
is string || obj
is DateTime
|| obj
is TimeSpan
)
133 // Checks an argument if it's possible to pass without marshalling and
134 // if not it will be added to arguments to be serialized
135 protected object MarshalArgument (object arg
, ref ArrayList args
) {
139 if (IsPossibleToIgnoreMarshal (arg
))
142 MarshalByRefObject mbr
= arg
as MarshalByRefObject
;
145 if (RemotingServices
.IsTransparentProxy(mbr
)) {
146 // We don't deal with this case yet
149 ObjRef objRef
= RemotingServices
.Marshal(mbr
);
150 return new CADObjRef(objRef
, System
.Threading
.Thread
.GetDomainID());
155 args
= new ArrayList();
159 // return position that the arg exists in the serialized list
160 return new CADArgHolder(args
.Count
- 1);
163 protected object UnmarshalArgument (object arg
, ArrayList args
) {
164 if (arg
== null) return null;
166 // Check if argument is an holder (then we know that it's a serialized argument)
167 CADArgHolder holder
= arg
as CADArgHolder
;
168 if (null != holder
) {
169 return args
[holder
.index
];
172 CADObjRef objref
= arg
as CADObjRef
;
173 if (null != objref
) {
174 string typeName
= string.Copy (objref
.TypeName
);
175 string uri
= string.Copy (objref
.URI
);
176 int domid
= objref
.SourceDomain
;
178 ChannelInfo cinfo
= new ChannelInfo (new CrossAppDomainData (domid
));
179 ObjRef localRef
= new ObjRef (typeName
, uri
, cinfo
);
180 return RemotingServices
.Unmarshal (localRef
);
185 Array argb
= (Array
)arg
;
188 // We can't use Array.CreateInstance (arg.GetType().GetElementType()) because
189 // GetElementType() returns a type from the source domain.
191 switch (Type
.GetTypeCode (arg
.GetType().GetElementType()))
193 case TypeCode
.Boolean
: argn
= new bool [argb
.Length
]; break;
194 case TypeCode
.Byte
: argn
= new Byte
[argb
.Length
]; break;
195 case TypeCode
.Char
: argn
= new Char
[argb
.Length
]; break;
196 case TypeCode
.Decimal
: argn
= new Decimal
[argb
.Length
]; break;
197 case TypeCode
.Double
: argn
= new Double
[argb
.Length
]; break;
198 case TypeCode
.Int16
: argn
= new Int16
[argb
.Length
]; break;
199 case TypeCode
.Int32
: argn
= new Int32
[argb
.Length
]; break;
200 case TypeCode
.Int64
: argn
= new Int64
[argb
.Length
]; break;
201 case TypeCode
.SByte
: argn
= new SByte
[argb
.Length
]; break;
202 case TypeCode
.Single
: argn
= new Single
[argb
.Length
]; break;
203 case TypeCode
.UInt16
: argn
= new UInt16
[argb
.Length
]; break;
204 case TypeCode
.UInt32
: argn
= new UInt32
[argb
.Length
]; break;
205 case TypeCode
.UInt64
: argn
= new UInt64
[argb
.Length
]; break;
206 default: throw new NotSupportedException ();
209 argb
.CopyTo (argn
, 0);
213 switch (Type
.GetTypeCode (arg
.GetType()))
215 case TypeCode
.Boolean
: return (bool)arg
;
216 case TypeCode
.Byte
: return (byte)arg
;
217 case TypeCode
.Char
: return (char)arg
;
218 case TypeCode
.Decimal
: return (decimal)arg
;
219 case TypeCode
.Double
: return (double)arg
;
220 case TypeCode
.Int16
: return (Int16
)arg
;
221 case TypeCode
.Int32
: return (Int32
)arg
;
222 case TypeCode
.Int64
: return (Int64
)arg
;
223 case TypeCode
.SByte
: return (SByte
)arg
;
224 case TypeCode
.Single
: return (Single
)arg
;
225 case TypeCode
.UInt16
: return (UInt16
)arg
;
226 case TypeCode
.UInt32
: return (UInt32
)arg
;
227 case TypeCode
.UInt64
: return (UInt64
)arg
;
228 case TypeCode
.String
: return string.Copy ((string) arg
);
229 case TypeCode
.DateTime
: return new DateTime (((DateTime
)arg
).Ticks
);
231 if (arg
is TimeSpan
) return new TimeSpan (((TimeSpan
)arg
).Ticks
);
232 if (arg
is IntPtr
) return (IntPtr
) arg
;
236 throw new NotSupportedException ("Parameter of type " + arg
.GetType () + " cannot be unmarshalled");
239 internal object [] MarshalArguments (object [] arguments
, ref ArrayList args
) {
240 object [] marshalledArgs
= new object [arguments
.Length
];
242 int total
= arguments
.Length
;
243 for (int i
= 0; i
< total
; i
++)
244 marshalledArgs
[i
] = MarshalArgument (arguments
[i
], ref args
);
246 return marshalledArgs
;
249 internal object [] UnmarshalArguments (object [] arguments
, ArrayList args
) {
250 object [] unmarshalledArgs
= new object [arguments
.Length
];
252 int total
= arguments
.Length
;
253 for (int i
= 0; i
< total
; i
++)
254 unmarshalledArgs
[i
] = UnmarshalArgument (arguments
[i
], args
);
256 return unmarshalledArgs
;
259 protected void SaveLogicalCallContext (IMethodMessage msg
, ref ArrayList serializeList
)
261 if (msg
.LogicalCallContext
!= null && msg
.LogicalCallContext
.HasInfo
)
263 if (serializeList
== null)
264 serializeList
= new ArrayList();
266 _callContext
= new CADArgHolder (serializeList
.Count
);
267 serializeList
.Add (msg
.LogicalCallContext
);
271 internal LogicalCallContext
GetLogicalCallContext (ArrayList args
)
273 if (null == _callContext
)
276 return (LogicalCallContext
) args
[_callContext
.index
];
280 // Used when passing a IMethodCallMessage between appdomains
281 internal class CADMethodCallMessage
: CADMessageBase
{
284 internal RuntimeMethodHandle MethodHandle
;
285 internal string FullTypeName
;
287 internal string Uri
{
293 static internal CADMethodCallMessage
Create (IMessage callMsg
) {
294 IMethodCallMessage msg
= callMsg
as IMethodCallMessage
;
298 return new CADMethodCallMessage (msg
);
301 internal CADMethodCallMessage (IMethodCallMessage callMsg
) {
303 MethodHandle
= callMsg
.MethodBase
.MethodHandle
;
304 FullTypeName
= callMsg
.MethodBase
.DeclaringType
.AssemblyQualifiedName
;
306 ArrayList serializeList
= null;
308 _propertyCount
= MarshalProperties (callMsg
.Properties
, ref serializeList
);
310 _args
= MarshalArguments ( callMsg
.Args
, ref serializeList
);
313 SaveLogicalCallContext (callMsg
, ref serializeList
);
315 // Serialize message data if needed
317 if (null != serializeList
) {
318 MemoryStream stm
= CADSerializer
.SerializeObject (serializeList
.ToArray());
319 _serializedArgs
= stm
.GetBuffer();
323 internal ArrayList
GetArguments () {
324 ArrayList ret
= null;
326 if (null != _serializedArgs
) {
327 object[] oret
= (object[]) CADSerializer
.DeserializeObject (new MemoryStream (_serializedArgs
));
328 ret
= new ArrayList (oret
);
329 _serializedArgs
= null;
335 internal object [] GetArgs (ArrayList args
) {
336 return UnmarshalArguments (_args
, args
);
339 internal int PropertiesCount
{
341 return _propertyCount
;
345 static Type
[] GetSignature (MethodBase methodBase
, bool load
)
347 ParameterInfo
[] pars
= methodBase
.GetParameters ();
348 Type
[] signature
= new Type
[pars
.Length
];
349 for (int n
=0; n
<pars
.Length
; n
++) {
350 // The parameter types may also be loaded from a different assembly, so we need
351 // to load them again
353 signature
[n
] = Type
.GetType (pars
[n
].ParameterType
.AssemblyQualifiedName
, true);
355 signature
[n
] = pars
[n
].ParameterType
;
360 internal MethodBase
GetMethod ()
362 MethodBase methodBase
= null;
363 Type tt
= Type
.GetType (FullTypeName
, true);
364 if (tt
.IsGenericType
|| tt
.IsGenericTypeDefinition
) {
365 methodBase
= MethodBase
.GetMethodFromHandleNoGenericCheck (MethodHandle
);
367 methodBase
= MethodBase
.GetMethodFromHandle (MethodHandle
);
370 if (tt
!= methodBase
.DeclaringType
) {
371 // The target domain has loaded the type from a different assembly.
372 // We need to locate the correct type and get the method from it
373 Type
[] signature
= GetSignature (methodBase
, true);
374 if (methodBase
.IsGenericMethod
) {
375 MethodBase
[] methods
= tt
.GetMethods (BindingFlags
.Public
|BindingFlags
.NonPublic
|BindingFlags
.Instance
);
376 Type
[] base_args
= methodBase
.GetGenericArguments ();
377 foreach (MethodBase method
in methods
) {
378 if (!method
.IsGenericMethod
|| method
.Name
!= methodBase
.Name
)
380 Type
[] method_args
= method
.GetGenericArguments ();
381 if (base_args
.Length
!= method_args
.Length
)
384 MethodInfo method_instance
= ((MethodInfo
) method
).MakeGenericMethod (base_args
);
385 Type
[] base_sig
= GetSignature (method_instance
, false);
386 if (base_sig
.Length
!= signature
.Length
) {
390 for (int i
= base_sig
.Length
- 1; i
>= 0; i
--) {
391 if (base_sig
[i
] != signature
[i
]) {
398 return method_instance
;
403 MethodBase mb
= tt
.GetMethod (methodBase
.Name
, BindingFlags
.Public
|BindingFlags
.NonPublic
|BindingFlags
.Instance
, null, signature
, null);
405 throw new RemotingException ("Method '" + methodBase
.Name
+ "' not found in type '" + tt
+ "'");
412 // Used when passing a IMethodReturnMessage between appdomains
413 internal class CADMethodReturnMessage
: CADMessageBase
{
415 CADArgHolder _exception
= null;
417 static internal CADMethodReturnMessage
Create (IMessage callMsg
) {
418 IMethodReturnMessage msg
= callMsg
as IMethodReturnMessage
;
422 return new CADMethodReturnMessage (msg
);
425 internal CADMethodReturnMessage(IMethodReturnMessage retMsg
) {
426 ArrayList serializeList
= null;
428 _propertyCount
= MarshalProperties (retMsg
.Properties
, ref serializeList
);
430 _returnValue
= MarshalArgument ( retMsg
.ReturnValue
, ref serializeList
);
431 _args
= MarshalArguments ( retMsg
.Args
, ref serializeList
);
433 if (null != retMsg
.Exception
) {
434 if (null == serializeList
)
435 serializeList
= new ArrayList();
437 _exception
= new CADArgHolder (serializeList
.Count
);
438 serializeList
.Add(retMsg
.Exception
);
442 SaveLogicalCallContext (retMsg
, ref serializeList
);
444 if (null != serializeList
) {
445 MemoryStream stm
= CADSerializer
.SerializeObject (serializeList
.ToArray());
446 _serializedArgs
= stm
.GetBuffer();
450 internal ArrayList
GetArguments () {
451 ArrayList ret
= null;
453 if (null != _serializedArgs
) {
454 object[] oret
= (object[]) CADSerializer
.DeserializeObject (new MemoryStream (_serializedArgs
));
455 ret
= new ArrayList (oret
);
456 _serializedArgs
= null;
462 internal object [] GetArgs (ArrayList args
) {
463 return UnmarshalArguments (_args
, args
);
466 internal object GetReturnValue (ArrayList args
) {
467 return UnmarshalArgument (_returnValue
, args
);
470 internal Exception
GetException(ArrayList args
) {
471 if (null == _exception
)
474 return (Exception
) args
[_exception
.index
];
477 internal int PropertiesCount
{
479 return _propertyCount
;