* RealProxy.cs: Added new internal method for getting the proxy type. It
[mono.git] / mcs / class / corlib / System.Runtime.Remoting.Proxies / RealProxy.cs
1 //
2 // System.Runtime.Remoting.Proxies.RealProxy.cs
3 //
4 // Authors:
5 //   Dietmar Maurer (dietmar@ximian.com)
6 //   Lluis Sanchez (lsg@ctv.es)
7 //   Patrik Torstensson
8 //
9 // (C) 2001 Ximian, Inc.  http://www.ximian.com
10 //
11
12 using System;
13 using System.Reflection;
14 using System.Runtime.Remoting;
15 using System.Runtime.Remoting.Messaging;
16 using System.Runtime.Remoting.Activation;
17 using System.Runtime.Remoting.Contexts;
18 using System.Runtime.CompilerServices;
19 using System.Runtime.Serialization;
20
21
22 namespace System.Runtime.Remoting.Proxies
23 {
24         internal class TransparentProxy {
25                 public RealProxy _rp;
26                 IntPtr _class;
27                 bool _custom_type_info;
28         }
29         
30         public abstract class RealProxy {
31
32                 Type class_to_proxy;
33                 internal Context _targetContext;
34                 MarshalByRefObject _server;
35                 internal Identity _objectIdentity;
36                 Object _objTP;
37                 object _stubData;
38
39                 protected RealProxy ()
40                 {
41                         throw new NotImplementedException ();
42                 }
43
44                 protected RealProxy (Type classToProxy) : this(classToProxy, (IntPtr) 0, null)
45                 {
46                 }
47
48                 internal RealProxy (Type classToProxy, ClientIdentity identity) : this(classToProxy, (IntPtr) 0, null)
49                 {
50                         _objectIdentity = identity;
51                 }
52
53                 protected RealProxy (Type classToProxy, IntPtr stub, object stubData)
54                 {
55                         if (!classToProxy.IsMarshalByRef && !classToProxy.IsInterface)
56                                 throw new ArgumentException("object must be MarshalByRef");
57
58                         this.class_to_proxy = classToProxy;
59
60                         // TODO: Fix stub
61                 }
62
63                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
64                 extern static Type InternalGetProxyType (object transparentProxy);
65                 
66                 public Type GetProxiedType() 
67                 {
68                         if (_objTP == null) {
69                                 if (class_to_proxy.IsInterface) return typeof(MarshalByRefObject);
70                                 else return class_to_proxy;
71                         }
72                         return InternalGetProxyType (_objTP);
73                 }
74
75                 public virtual ObjRef CreateObjRef (Type requestedType)
76                 {
77                         return RemotingServices.Marshal ((MarshalByRefObject) GetTransparentProxy(), null, requestedType);
78                 }
79
80                 public virtual void GetObjectData (SerializationInfo info, StreamingContext context)
81                 {
82                         Object obj = GetTransparentProxy();\r
83                         RemotingServices.GetObjectData (obj, info, context);            \r
84                 }
85                 
86                 internal Identity ObjectIdentity
87                 {
88                         get { return _objectIdentity; }
89                         set { _objectIdentity = value; }
90                 }
91                 
92                 [MonoTODO]
93                 public virtual IntPtr GetCOMIUnknown (bool fIsMarshalled)
94                 {
95                         throw new NotImplementedException ();
96                 }
97                 
98                 [MonoTODO]
99                 public virtual void SetCOMIUnknown (IntPtr i)
100                 {
101                         throw new NotImplementedException ();
102                 }
103                 
104                 [MonoTODO]
105                 public virtual IntPtr SupportsInterface (ref Guid iid)
106                 {
107                         throw new NotImplementedException ();
108                 }
109                 
110                 public static object GetStubData (RealProxy rp)
111                 {
112                         return rp._stubData;
113                 }
114                 
115                 public static void SetStubData (RealProxy rp, object stubData)
116                 {
117                         rp._stubData = stubData;
118                 }
119
120                 public abstract IMessage Invoke (IMessage msg);
121
122                 /* this is called from unmanaged code */
123                 internal static object PrivateInvoke (RealProxy rp, IMessage msg, out Exception exc,
124                                                       out object [] out_args)
125                 {
126                         MonoMethodMessage mMsg = (MonoMethodMessage) msg;
127                         mMsg.LogicalCallContext = CallContext.CreateLogicalCallContext();
128                         
129                         if (mMsg.CallType == CallType.BeginInvoke) 
130                                 mMsg.AsyncResult.CallMessage = mMsg;    // TODO: do this in the runtime
131
132                         IMethodReturnMessage res_msg = null;
133                         res_msg = (IMethodReturnMessage)rp.Invoke (msg);
134                         
135                         if (res_msg.LogicalCallContext != null && res_msg.LogicalCallContext.HasInfo)
136                                 CallContext.UpdateCurrentCallContext (res_msg.LogicalCallContext);
137
138                         exc = res_msg.Exception;
139
140                         // todo: remove throw exception from the runtime invoke
141                         if (null != exc) {
142                                 out_args = null;
143                                 throw exc.FixRemotingException();
144                         }
145                         else if (res_msg is IConstructionReturnMessage || mMsg.CallType == CallType.BeginInvoke) {
146                                 out_args = res_msg.OutArgs;
147                         }
148                         else if (mMsg.CallType == CallType.Sync) {
149                                 out_args = ProcessResponse (res_msg, mMsg);
150                         }
151                         else if (mMsg.CallType == CallType.EndInvoke) {
152                                 out_args = ProcessResponse (res_msg, mMsg.AsyncResult.CallMessage);
153                         }
154                         else {
155                                 out_args = res_msg.OutArgs;
156                         }
157
158                         return res_msg.ReturnValue;
159                 }
160
161                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
162                 internal extern virtual object InternalGetTransparentProxy (string className);
163
164                 public virtual object GetTransparentProxy () 
165                 {
166                         if (_objTP == null) 
167                         {
168                                 string name;
169                                 IRemotingTypeInfo rti = this as IRemotingTypeInfo;
170                                 
171                                 if (rti != null) {
172                                         name = rti.TypeName;
173                                         if (name == typeof(MarshalByRefObject).AssemblyQualifiedName)
174                                                 name = class_to_proxy.AssemblyQualifiedName;
175                                 }
176                                 else
177                                         name = class_to_proxy.AssemblyQualifiedName;
178                                         
179                                 _objTP = InternalGetTransparentProxy (name);
180                         }
181                         return _objTP;
182                 }
183
184                 [MonoTODO]
185                 public IConstructionReturnMessage InitializeServerObject(IConstructionCallMessage ctorMsg)
186                 {
187                         throw new NotImplementedException();
188                 }
189
190                 protected void AttachServer(MarshalByRefObject s)
191                 {
192                         _server = s;
193                 }
194
195                 protected MarshalByRefObject DetachServer()
196                 {
197                         MarshalByRefObject ob = _server;
198                         _server = null;
199                         return ob;
200                 }
201
202                 protected MarshalByRefObject GetUnwrappedServer()
203                 {
204                         return _server;
205                 }
206
207                 static object[] ProcessResponse (IMethodReturnMessage mrm, IMethodCallMessage call)
208                 {
209                         // Check return type
210
211                         MethodInfo mi = (MethodInfo) call.MethodBase;
212                         if (mrm.ReturnValue != null && !mi.ReturnType.IsInstanceOfType (mrm.ReturnValue))
213                                 throw new RemotingException ("Return value has an invalid type");
214
215                         // Check out parameters
216
217                         if (mrm.OutArgCount > 0)
218                         {
219                                 ParameterInfo[] parameters = mi.GetParameters();
220                                 int no = 0;
221                                 foreach (ParameterInfo par in parameters)
222                                         if (par.ParameterType.IsByRef) no++;
223                                 
224                                 object[] outArgs = new object [no];
225                                 int narg = 0;
226                                 int nout = 0;
227         
228                                 foreach (ParameterInfo par in parameters)
229                                 {
230                                         if (par.IsOut && !par.ParameterType.IsByRef)
231                                         {
232                                                 // Special marshalling required
233                                                 
234                                                 object outArg = mrm.GetOutArg (nout++);
235                                                 if (outArg != null) {
236                                                         object local = call.GetArg (par.Position);
237                                                         if (local == null) throw new RemotingException ("Unexpected null value in local out parameter '" + par.Position + " " + par.Name + "'");
238                                                         RemotingServices.UpdateOutArgObject (par, local, outArg);
239                                                 }
240                                         }
241                                         else if (par.ParameterType.IsByRef)
242                                         {
243                                                 object outArg = mrm.GetOutArg (nout++);
244                                                 if (outArg != null && !par.ParameterType.IsInstanceOfType (outArg))
245                                                 {
246                                                         throw new RemotingException ("Return argument '" + par.Name + "' has an invalid type");
247                                                 }
248                                                 outArgs [narg++] = outArg;
249                                         }
250                                 }
251                                 return outArgs;
252                         }
253                         else
254                                 return new object [0];
255                 }
256         }
257 }