2004-02-13 Sebastien Pouliot <sebastien@ximian.com>
[mono.git] / mcs / class / corlib / System.Runtime.Remoting.Proxies / RealProxy.cs
index 079d8075b733a6e023a1cc5184d979e724de10ca..84eb8823ca95a62f6ad5a4d43f4b81478d037b62 100644 (file)
@@ -4,14 +4,19 @@
 // Authors:
 //   Dietmar Maurer (dietmar@ximian.com)
 //   Lluis Sanchez (lsg@ctv.es)
+//   Patrik Torstensson
 //
 // (C) 2001 Ximian, Inc.  http://www.ximian.com
 //
 
 using System;
+using System.Reflection;
 using System.Runtime.Remoting;
 using System.Runtime.Remoting.Messaging;
+using System.Runtime.Remoting.Activation;
+using System.Runtime.Remoting.Contexts;
 using System.Runtime.CompilerServices;
+using System.Runtime.Serialization;
 
 
 namespace System.Runtime.Remoting.Proxies
@@ -19,42 +24,92 @@ namespace System.Runtime.Remoting.Proxies
        internal class TransparentProxy {
                public RealProxy _rp;
                IntPtr _class;
+               bool _custom_type_info;
        }
        
        public abstract class RealProxy {
 
                Type class_to_proxy;
-               Identity _objectIdentity;
+               internal Context _targetContext;
+               MarshalByRefObject _server;
+               internal Identity _objectIdentity;
+               Object _objTP;
+               object _stubData;
 
                protected RealProxy ()
                {
                        throw new NotImplementedException ();
                }
 
-               protected RealProxy (Type classToProxy)
+               protected RealProxy (Type classToProxy) : this(classToProxy, (IntPtr) 0, null)
                {
-                       this.class_to_proxy = classToProxy;
                }
 
-               internal RealProxy (Type classToProxy, Identity identity)
+               internal RealProxy (Type classToProxy, ClientIdentity identity) : this(classToProxy, (IntPtr) 0, null)
                {
-                       this.class_to_proxy = classToProxy;
                        _objectIdentity = identity;
                }
 
                protected RealProxy (Type classToProxy, IntPtr stub, object stubData)
                {
-                       throw new NotImplementedException ();
+                       if (!classToProxy.IsMarshalByRef && !classToProxy.IsInterface)
+                               throw new ArgumentException("object must be MarshalByRef");
+
+                       this.class_to_proxy = classToProxy;
+
+                       // TODO: Fix stub
+                       _objTP = InternalGetTransparentProxy();
+               }
+
+               public Type GetProxiedType() 
+               {
+                       if (class_to_proxy.IsInterface) return typeof (MarshalByRefObject);
+                       else return class_to_proxy;
                }
 
                public virtual ObjRef CreateObjRef (Type requestedType)
                {
-                       return _objectIdentity.CreateObjRef (requestedType);
+                       return RemotingServices.Marshal ((MarshalByRefObject) GetTransparentProxy(), null, requestedType);
                }
 
+               public virtual void GetObjectData (SerializationInfo info, StreamingContext context)
+               {
+                       Object obj = GetTransparentProxy();\r
+                       RemotingServices.GetObjectData (obj, info, context);            \r
+               }
+               
                internal Identity ObjectIdentity
                {
                        get { return _objectIdentity; }
+                       set { _objectIdentity = value; }
+               }
+               
+               [MonoTODO]
+               public virtual IntPtr GetCOMIUnknown (bool fIsMarshalled)
+               {
+                       throw new NotImplementedException ();
+               }
+               
+               [MonoTODO]
+               public virtual void SetCOMIUnknown (IntPtr i)
+               {
+                       throw new NotImplementedException ();
+               }
+               
+               [MonoTODO]
+               public virtual IntPtr SupportsInterface (ref Guid iid)
+               {
+                       throw new NotImplementedException ();
+               }
+               
+               public static object GetStubData (RealProxy rp)
+               {
+                       return rp._stubData;
+               }
+               
+               public static void SetStubData (RealProxy rp, object stubData)
+               {
+                       rp._stubData = stubData;
                }
 
                public abstract IMessage Invoke (IMessage msg);
@@ -63,16 +118,119 @@ namespace System.Runtime.Remoting.Proxies
                internal static object PrivateInvoke (RealProxy rp, IMessage msg, out Exception exc,
                                                      out object [] out_args)
                {
+                       MonoMethodMessage mMsg = (MonoMethodMessage) msg;
+                       mMsg.LogicalCallContext = CallContext.CreateLogicalCallContext();
+                       
+                       if (mMsg.CallType == CallType.BeginInvoke) 
+                               mMsg.AsyncResult.CallMessage = mMsg;    // TODO: do this in the runtime
+
                        IMethodReturnMessage res_msg = (IMethodReturnMessage)rp.Invoke (msg);
 
+                       if (res_msg.LogicalCallContext != null && res_msg.LogicalCallContext.HasInfo)
+                               CallContext.UpdateCurrentCallContext (res_msg.LogicalCallContext);
+
                        exc = res_msg.Exception;
-                       out_args = res_msg.OutArgs;
+
+                       // todo: remove throw exception from the runtime invoke
+                       if (null != exc) {
+                               out_args = null;
+                               throw exc.FixRemotingException();
+                       }
+                       else if (res_msg is IConstructionReturnMessage || mMsg.CallType == CallType.BeginInvoke) {
+                               out_args = res_msg.OutArgs;
+                       }
+                       else if (mMsg.CallType == CallType.Sync) {
+                               out_args = ProcessResponse (res_msg, mMsg);
+                       }
+                       else if (mMsg.CallType == CallType.EndInvoke) {
+                               out_args = ProcessResponse (res_msg, mMsg.AsyncResult.CallMessage);
+                       }
+                       else {
+                               out_args = res_msg.OutArgs;
+                       }
+
                        return res_msg.ReturnValue;
                }
 
                [MethodImplAttribute(MethodImplOptions.InternalCall)]
-               public extern virtual object GetTransparentProxy ();
+               internal extern virtual object InternalGetTransparentProxy ();
+
+               public virtual object GetTransparentProxy () 
+               {
+                       return _objTP;
+               }
+
+               [MonoTODO]
+               public IConstructionReturnMessage InitializeServerObject(IConstructionCallMessage ctorMsg)
+               {
+                       throw new NotImplementedException();
+               }
+
+               protected void AttachServer(MarshalByRefObject s)
+               {
+                       _server = s;
+               }
+
+               protected MarshalByRefObject DetachServer()
+               {
+                       MarshalByRefObject ob = _server;
+                       _server = null;
+                       return ob;
+               }
+
+               protected MarshalByRefObject GetUnwrappedServer()
+               {
+                       return _server;
+               }
+
+               static object[] ProcessResponse (IMethodReturnMessage mrm, IMethodCallMessage call)
+               {
+                       // Check return type
+
+                       MethodInfo mi = (MethodInfo) call.MethodBase;
+                       if (mrm.ReturnValue != null && !mi.ReturnType.IsInstanceOfType (mrm.ReturnValue))
+                               throw new RemotingException ("Return value has an invalid type");
+
+                       // Check out parameters
+
+                       if (mrm.OutArgCount > 0)
+                       {
+                               ParameterInfo[] parameters = mi.GetParameters();
+                               int no = 0;
+                               foreach (ParameterInfo par in parameters)
+                                       if (par.ParameterType.IsByRef) no++;
+                               
+                               object[] outArgs = new object [no];
+                               int narg = 0;
+                               int nout = 0;
        
+                               foreach (ParameterInfo par in parameters)
+                               {
+                                       if (par.IsOut && !par.ParameterType.IsByRef)
+                                       {
+                                               // Special marshalling required
+                                               
+                                               object outArg = mrm.GetOutArg (nout++);
+                                               if (outArg != null) {
+                                                       object local = call.GetArg (par.Position);
+                                                       if (local == null) throw new RemotingException ("Unexpected null value in local out parameter '" + par.Position + " " + par.Name + "'");
+                                                       RemotingServices.UpdateOutArgObject (par, local, outArg);
+                                               }
+                                       }
+                                       else if (par.ParameterType.IsByRef)
+                                       {
+                                               object outArg = mrm.GetOutArg (nout++);
+                                               if (outArg != null && !par.ParameterType.IsInstanceOfType (outArg))
+                                               {
+                                                       throw new RemotingException ("Return argument '" + par.Name + "' has an invalid type");
+                                               }
+                                               outArgs [narg++] = outArg;
+                                       }
+                               }
+                               return outArgs;
+                       }
+                       else
+                               return new object [0];
+               }
        }
-
 }