2 // System.Runtime.Remoting.Proxies.RealProxy.cs
5 // Dietmar Maurer (dietmar@ximian.com)
6 // Lluis Sanchez (lsg@ctv.es)
9 // (C) 2001 Ximian, Inc. http://www.ximian.com
13 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
15 // Permission is hereby granted, free of charge, to any person obtaining
16 // a copy of this software and associated documentation files (the
17 // "Software"), to deal in the Software without restriction, including
18 // without limitation the rights to use, copy, modify, merge, publish,
19 // distribute, sublicense, and/or sell copies of the Software, and to
20 // permit persons to whom the Software is furnished to do so, subject to
21 // the following conditions:
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
26 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
30 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
31 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
32 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36 using System
.Reflection
;
37 using System
.Runtime
.Remoting
;
38 using System
.Runtime
.Remoting
.Messaging
;
39 using System
.Runtime
.Remoting
.Activation
;
40 using System
.Runtime
.Remoting
.Contexts
;
41 using System
.Runtime
.CompilerServices
;
42 using System
.Runtime
.Serialization
;
43 using System
.Runtime
.InteropServices
;
44 using System
.Threading
;
46 namespace System
.Runtime
.Remoting
.Proxies
48 #pragma warning disable 169, 649
49 [StructLayout (LayoutKind
.Sequential
)]
50 internal class TransparentProxy
{
52 Mono
.RuntimeRemoteClassHandle _class
;
53 bool _custom_type_info
;
55 unsafe internal RuntimeType
GetProxyType () {
56 RuntimeTypeHandle h
= _class
.ProxyClass
.GetTypeHandle ();
57 return (RuntimeType
)Type
.GetTypeFromHandle (h
);
60 bool IsContextBoundObject
{
61 get { return GetProxyType ().IsContextful; }
64 Context TargetContext
{
65 get { return _rp._targetContext; }
68 bool InCurrentContext () {
69 return IsContextBoundObject
&& Object
.ReferenceEquals (TargetContext
, Thread
.CurrentContext
);
72 internal object LoadRemoteFieldNew (IntPtr classPtr
, IntPtr fieldPtr
) {
73 Mono
.RuntimeClassHandle classHandle
= new Mono
.RuntimeClassHandle (classPtr
);
74 RuntimeFieldHandle fieldHandle
= new RuntimeFieldHandle (fieldPtr
);
75 RuntimeTypeHandle typeHandle
= classHandle
.GetTypeHandle ();
77 FieldInfo field
= FieldInfo
.GetFieldFromHandle (fieldHandle
);
79 if (InCurrentContext ()) {
80 object o
= _rp
._server
;
81 return field
.GetValue(o
);
84 string typeName
= Type
.GetTypeFromHandle(typeHandle
).FullName
;
85 string fieldName
= field
.Name
;
86 object[] inArgs
= new object[] { typeName
,
88 object[] outArgsMsg
= new object[1];
89 MethodInfo minfo
= typeof(object).GetMethod("FieldGetter", BindingFlags
.NonPublic
| BindingFlags
.Instance
);
91 throw new MissingMethodException ("System.Object", "FieldGetter");
92 MonoMethodMessage msg
= new MonoMethodMessage (minfo
, inArgs
, outArgsMsg
);
95 RealProxy
.PrivateInvoke (_rp
, msg
, out exc
, out outArgs
);
101 internal void StoreRemoteField (IntPtr classPtr
, IntPtr fieldPtr
, object arg
) {
102 Mono
.RuntimeClassHandle classHandle
= new Mono
.RuntimeClassHandle (classPtr
);
103 RuntimeFieldHandle fieldHandle
= new RuntimeFieldHandle (fieldPtr
);
104 RuntimeTypeHandle typeHandle
= classHandle
.GetTypeHandle ();
105 FieldInfo field
= FieldInfo
.GetFieldFromHandle (fieldHandle
);
107 if (InCurrentContext ()) {
108 object o
= _rp
._server
;
109 field
.SetValue (o
, arg
);
113 string typeName
= Type
.GetTypeFromHandle (typeHandle
).FullName
;
114 string fieldName
= field
.Name
;
115 object [] inArgs
= new object[] { typeName
,
118 MethodInfo minfo
= typeof(object).GetMethod ("FieldSetter", BindingFlags
.NonPublic
| BindingFlags
.Instance
);
120 throw new MissingMethodException ("System.Object", "FieldSetter");
122 MonoMethodMessage msg
= new MonoMethodMessage (minfo
, inArgs
, null);
125 RealProxy
.PrivateInvoke (_rp
, msg
, out exc
, out outArgs
);
131 #pragma warning restore 169, 649
134 [StructLayout (LayoutKind
.Sequential
)]
135 public abstract class RealProxy
{
136 // other classes visible to the runtime
137 // derive from this class so keep these locals
138 // in sync with the definition RealProxy
139 // in object-internals.h
141 #pragma warning disable 169, 414
142 #region Sync with object-internals.h
144 internal Context _targetContext
;
145 internal MarshalByRefObject _server
;
146 int _targetDomainId
= -1;
147 internal string _targetUri
;
148 internal Identity _objectIdentity
;
152 #pragma warning restore 169, 414
154 protected RealProxy ()
158 protected RealProxy (Type classToProxy
) : this(classToProxy
, IntPtr
.Zero
, null)
162 internal RealProxy (Type classToProxy
, ClientIdentity identity
) : this(classToProxy
, IntPtr
.Zero
, null)
164 _objectIdentity
= identity
;
167 protected RealProxy (Type classToProxy
, IntPtr stub
, object stubData
)
169 if (!classToProxy
.IsMarshalByRef
&& !classToProxy
.IsInterface
)
170 throw new ArgumentException("object must be MarshalByRef");
172 this.class_to_proxy
= classToProxy
;
174 if (stub
!= IntPtr
.Zero
)
175 throw new NotSupportedException ("stub is not used in Mono");
178 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
179 extern static Type
InternalGetProxyType (object transparentProxy
);
181 public Type
GetProxiedType()
183 if (_objTP
== null) {
184 if (class_to_proxy
.IsInterface
) return typeof(MarshalByRefObject
);
185 else return class_to_proxy
;
187 return InternalGetProxyType (_objTP
);
190 public virtual ObjRef
CreateObjRef (Type requestedType
)
192 return RemotingServices
.Marshal ((MarshalByRefObject
) GetTransparentProxy(), null, requestedType
);
195 public virtual void GetObjectData (SerializationInfo info
, StreamingContext context
)
197 Object obj
= GetTransparentProxy();
198 RemotingServices
.GetObjectData (obj
, info
, context
);
201 internal Identity ObjectIdentity
203 get { return _objectIdentity; }
204 set { _objectIdentity = value; }
208 public virtual IntPtr
GetCOMIUnknown (bool fIsMarshalled
)
210 throw new NotImplementedException ();
214 public virtual void SetCOMIUnknown (IntPtr i
)
216 throw new NotImplementedException ();
220 public virtual IntPtr
SupportsInterface (ref Guid iid
)
222 throw new NotImplementedException ();
225 public static object GetStubData (RealProxy rp
)
230 public static void SetStubData (RealProxy rp
, object stubData
)
232 rp
._stubData
= stubData
;
235 public abstract IMessage
Invoke (IMessage msg
);
237 /* this is called from unmanaged code */
238 internal static object PrivateInvoke (RealProxy rp
, IMessage msg
, out Exception exc
,
239 out object [] out_args
)
241 MonoMethodMessage mMsg
= (MonoMethodMessage
) msg
;
242 mMsg
.LogicalCallContext
= Thread
.CurrentThread
.GetMutableExecutionContext().LogicalCallContext
;
243 CallType call_type
= mMsg
.CallType
;
244 bool is_remproxy
= (rp
is RemotingProxy
);
247 IMethodReturnMessage res_msg
= null;
249 if (call_type
== CallType
.BeginInvoke
)
250 // todo: set CallMessage in runtime instead
251 mMsg
.AsyncResult
.CallMessage
= mMsg
;
253 if (call_type
== CallType
.EndInvoke
)
254 res_msg
= (IMethodReturnMessage
)mMsg
.AsyncResult
.EndInvoke ();
256 // Check for constructor msg
257 if (mMsg
.MethodBase
.IsConstructor
)
260 res_msg
= (IMethodReturnMessage
) (rp
as RemotingProxy
).ActivateRemoteObject ((IMethodMessage
) msg
);
262 msg
= new ConstructionCall (rp
.GetProxiedType ());
270 res_msg
= (IMethodReturnMessage
)rp
.Invoke (msg
);
271 } catch (Exception ex
) {
273 if (call_type
== CallType
.BeginInvoke
) {
274 // If async dispatch crashes, don't propagate the exception.
275 // The exception will be raised when calling EndInvoke.
276 mMsg
.AsyncResult
.SyncProcessMessage (new ReturnMessage (ex
, msg
as IMethodCallMessage
));
277 res_msg
= new ReturnMessage (null, null, 0, null, msg
as IMethodCallMessage
);
282 // Note, from begining this code used AsyncResult.IsCompleted for
283 // checking if it was a remoting or custom proxy, but in some
284 // cases the remoting proxy finish before the call returns
285 // causing this method to be called, therefore causing all kind of bugs.
286 if ((!is_remproxy
) && call_type
== CallType
.BeginInvoke
&& !failed
)
288 IMessage asyncMsg
= null;
290 // allow calltype EndInvoke to finish
291 asyncMsg
= mMsg
.AsyncResult
.SyncProcessMessage (res_msg
as IMessage
);
292 out_args
= res_msg
.OutArgs
;
293 res_msg
= new ReturnMessage (asyncMsg
, null, 0, null, res_msg
as IMethodCallMessage
);
297 if (res_msg
.LogicalCallContext
!= null && res_msg
.LogicalCallContext
.HasInfo
) {
298 Thread
.CurrentThread
.GetMutableExecutionContext().LogicalCallContext
.Merge (res_msg
.LogicalCallContext
);
301 exc
= res_msg
.Exception
;
303 // todo: remove throw exception from the runtime invoke
306 throw exc
.FixRemotingException();
308 else if (res_msg
is IConstructionReturnMessage
) {
309 if (out_args
== null)
310 out_args
= res_msg
.OutArgs
;
312 else if (mMsg
.CallType
== CallType
.BeginInvoke
) {
313 // We don't have OutArgs in this case.
315 else if (mMsg
.CallType
== CallType
.Sync
) {
316 out_args
= ProcessResponse (res_msg
, mMsg
);
318 else if (mMsg
.CallType
== CallType
.EndInvoke
) {
319 out_args
= ProcessResponse (res_msg
, mMsg
.AsyncResult
.CallMessage
);
322 if (out_args
== null)
323 out_args
= res_msg
.OutArgs
;
326 return res_msg
.ReturnValue
;
329 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
330 internal extern virtual object InternalGetTransparentProxy (string className
);
332 public virtual object GetTransparentProxy ()
337 IRemotingTypeInfo rti
= this as IRemotingTypeInfo
;
341 if (name
== null || name
== typeof(MarshalByRefObject
).AssemblyQualifiedName
)
342 name
= class_to_proxy
.AssemblyQualifiedName
;
345 name
= class_to_proxy
.AssemblyQualifiedName
;
347 _objTP
= InternalGetTransparentProxy (name
);
354 public IConstructionReturnMessage
InitializeServerObject(IConstructionCallMessage ctorMsg
)
356 throw new NotImplementedException();
359 protected void AttachServer(MarshalByRefObject s
)
364 protected MarshalByRefObject
DetachServer()
366 MarshalByRefObject ob
= _server
;
371 protected MarshalByRefObject
GetUnwrappedServer()
376 internal void SetTargetDomain (int domainId
)
378 _targetDomainId
= domainId
;
381 // Called by the runtime
382 internal object GetAppDomainTarget ()
384 if (_server
== null) {
385 ClientActivatedIdentity identity
= RemotingServices
.GetIdentityForUri (_targetUri
) as ClientActivatedIdentity
;
386 if (identity
== null) throw new RemotingException ("Server for uri '" + _targetUri
+ "' not found");
387 _server
= identity
.GetServerObject ();
392 static object[] ProcessResponse (IMethodReturnMessage mrm
, MonoMethodMessage call
)
396 MethodInfo mi
= (MethodInfo
) call
.MethodBase
;
397 if (mrm
.ReturnValue
!= null && !mi
.ReturnType
.IsInstanceOfType (mrm
.ReturnValue
))
398 throw new InvalidCastException ("Return value has an invalid type");
400 // Check out parameters
405 if (call
.NeedsOutProcessing (out no
))
407 ParameterInfo
[] parameters
= mi
.GetParameters();
408 object[] outArgs
= new object [no
];
411 foreach (ParameterInfo par
in parameters
)
413 if (par
.IsOut
&& !par
.ParameterType
.IsByRef
)
415 // Special marshalling required
416 object outArg
= par
.Position
< mrm
.ArgCount
? mrm
.GetArg (par
.Position
) : null;
417 if (outArg
!= null) {
418 object local
= call
.GetArg (par
.Position
);
419 if (local
== null) throw new RemotingException ("Unexpected null value in local out parameter '" + par
.Name
+ "'");
420 RemotingServices
.UpdateOutArgObject (par
, local
, outArg
);
423 else if (par
.ParameterType
.IsByRef
)
425 object outArg
= par
.Position
< mrm
.ArgCount
? mrm
.GetArg (par
.Position
) : null;
426 if (outArg
!= null && !par
.ParameterType
.GetElementType ().IsInstanceOfType (outArg
))
428 throw new InvalidCastException ("Return argument '" + par
.Name
+ "' has an invalid type");
430 outArgs
[narg
++] = outArg
;
436 return new object [0];