* AppDomainSetup.cs: If relative paths are used they should be
[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                         _objTP = InternalGetTransparentProxy();
62                 }
63
64                 public Type GetProxiedType() 
65                 {
66                         if (class_to_proxy.IsInterface) return typeof (MarshalByRefObject);
67                         else return class_to_proxy;
68                 }
69
70                 public virtual ObjRef CreateObjRef (Type requestedType)
71                 {
72                         return RemotingServices.Marshal ((MarshalByRefObject) GetTransparentProxy(), null, requestedType);
73                 }
74
75                 public virtual void GetObjectData (SerializationInfo info, StreamingContext context)
76                 {
77                         Object obj = GetTransparentProxy();\r
78                         RemotingServices.GetObjectData (obj, info, context);            \r
79                 }
80                 
81                 internal Identity ObjectIdentity
82                 {
83                         get { return _objectIdentity; }
84                         set { _objectIdentity = value; }
85                 }
86                 
87                 [MonoTODO]
88                 public virtual IntPtr GetCOMIUnknown (bool fIsMarshalled)
89                 {
90                         throw new NotImplementedException ();
91                 }
92                 
93                 [MonoTODO]
94                 public virtual void SetCOMIUnknown (IntPtr i)
95                 {
96                         throw new NotImplementedException ();
97                 }
98                 
99                 [MonoTODO]
100                 public virtual IntPtr SupportsInterface (ref Guid iid)
101                 {
102                         throw new NotImplementedException ();
103                 }
104                 
105                 public static object GetStubData (RealProxy rp)
106                 {
107                         return rp._stubData;
108                 }
109                 
110                 public static void SetStubData (RealProxy rp, object stubData)
111                 {
112                         rp._stubData = stubData;
113                 }
114
115                 public abstract IMessage Invoke (IMessage msg);
116
117                 /* this is called from unmanaged code */
118                 internal static object PrivateInvoke (RealProxy rp, IMessage msg, out Exception exc,
119                                                       out object [] out_args)
120                 {
121                         MonoMethodMessage mMsg = (MonoMethodMessage) msg;
122                         mMsg.LogicalCallContext = CallContext.CreateLogicalCallContext();
123                         
124                         if (mMsg.CallType == CallType.BeginInvoke) 
125                                 mMsg.AsyncResult.CallMessage = mMsg;    // TODO: do this in the runtime
126
127                         IMethodReturnMessage res_msg = (IMethodReturnMessage)rp.Invoke (msg);
128
129                         if (res_msg.LogicalCallContext != null && res_msg.LogicalCallContext.HasInfo)
130                                 CallContext.UpdateCurrentCallContext (res_msg.LogicalCallContext);
131
132                         exc = res_msg.Exception;
133
134                         // todo: remove throw exception from the runtime invoke
135                         if (null != exc) {
136                                 out_args = null;
137                                 throw exc.FixRemotingException();
138                         }
139                         else if (res_msg is IConstructionReturnMessage || mMsg.CallType == CallType.BeginInvoke) {
140                                 out_args = res_msg.OutArgs;
141                         }
142                         else if (mMsg.CallType == CallType.Sync) {
143                                 out_args = ProcessResponse (res_msg, mMsg);
144                         }
145                         else if (mMsg.CallType == CallType.EndInvoke) {
146                                 out_args = ProcessResponse (res_msg, mMsg.AsyncResult.CallMessage);
147                         }
148                         else {
149                                 out_args = res_msg.OutArgs;
150                         }
151
152                         return res_msg.ReturnValue;
153                 }
154
155                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
156                 internal extern virtual object InternalGetTransparentProxy ();
157
158                 public virtual object GetTransparentProxy () 
159                 {
160                         return _objTP;
161                 }
162
163                 [MonoTODO]
164                 public IConstructionReturnMessage InitializeServerObject(IConstructionCallMessage ctorMsg)
165                 {
166                         throw new NotImplementedException();
167                 }
168
169                 protected void AttachServer(MarshalByRefObject s)
170                 {
171                         _server = s;
172                 }
173
174                 protected MarshalByRefObject DetachServer()
175                 {
176                         MarshalByRefObject ob = _server;
177                         _server = null;
178                         return ob;
179                 }
180
181                 protected MarshalByRefObject GetUnwrappedServer()
182                 {
183                         return _server;
184                 }
185
186                 static object[] ProcessResponse (IMethodReturnMessage mrm, IMethodCallMessage call)
187                 {
188                         // Check return type
189
190                         MethodInfo mi = (MethodInfo) call.MethodBase;
191                         if (mrm.ReturnValue != null && !mi.ReturnType.IsInstanceOfType (mrm.ReturnValue))
192                                 throw new RemotingException ("Return value has an invalid type");
193
194                         // Check out parameters
195
196                         if (mrm.OutArgCount > 0)
197                         {
198                                 ParameterInfo[] parameters = mi.GetParameters();
199                                 int no = 0;
200                                 foreach (ParameterInfo par in parameters)
201                                         if (par.ParameterType.IsByRef) no++;
202                                 
203                                 object[] outArgs = new object [no];
204                                 int narg = 0;
205                                 int nout = 0;
206         
207                                 foreach (ParameterInfo par in parameters)
208                                 {
209                                         if (par.IsOut && !par.ParameterType.IsByRef)
210                                         {
211                                                 // Special marshalling required
212                                                 
213                                                 object outArg = mrm.GetOutArg (nout++);
214                                                 if (outArg != null) {
215                                                         object local = call.GetArg (par.Position);
216                                                         if (local == null) throw new RemotingException ("Unexpected null value in local out parameter '" + par.Position + " " + par.Name + "'");
217                                                         RemotingServices.UpdateOutArgObject (par, local, outArg);
218                                                 }
219                                         }
220                                         else if (par.ParameterType.IsByRef)
221                                         {
222                                                 object outArg = mrm.GetOutArg (nout++);
223                                                 if (outArg != null && !par.ParameterType.IsInstanceOfType (outArg))
224                                                 {
225                                                         throw new RemotingException ("Return argument '" + par.Name + "' has an invalid type");
226                                                 }
227                                                 outArgs [narg++] = outArg;
228                                         }
229                                 }
230                                 return outArgs;
231                         }
232                         else
233                                 return new object [0];
234                 }
235         }
236 }