remotingproxy.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / whidbey / netfxsp / ndp / clr / src / BCL / System / Runtime / Remoting / remotingproxy.cs / 1 / remotingproxy.cs

                            // ==++== 
//
//   Copyright (c) Microsoft Corporation.  All rights reserved.
//
// ==--== 
/*============================================================
** 
** File:    RemotingProxy.cs 
**
** 
** Purpose: Defines the general purpose remoting proxy
**
**
===========================================================*/ 
namespace System.Runtime.Remoting.Proxies {
    using System.Threading; 
    using System.Runtime.Remoting.Activation; 
    using System.Runtime.Remoting.Messaging;
    using System.Runtime.Remoting.Contexts; 
    using System.Runtime.Remoting.Channels;
    using System;
    using MethodInfo = System.Reflection.MethodInfo;
    using MethodBase = System.Reflection.MethodBase; 
    using System.Globalization;
    // Remoting proxy 
    internal class RemotingProxy : RealProxy, IRemotingTypeInfo 
    {
        // Static Fields 
        private static MethodInfo _getTypeMethod = typeof(System.Object).GetMethod("GetType");
        private static MethodInfo _getHashCodeMethod = typeof(System.Object).GetMethod("GetHashCode");

        private static Type s_typeofObject = typeof(System.Object); 
        private static Type s_typeofMarshalByRefObject = typeof(System.MarshalByRefObject);
 
        //*******************WARNING****************************************** 
        // If you change the names of these fields then change the corresponding
        // names in remoting.cpp 
        //*******************************************************************
        private ConstructorCallMessage _ccm;
        private int _ctorThread;
 

        // Constructor 
        public RemotingProxy(Type serverType) 
        : base(serverType)
        { 
        }

        private RemotingProxy()
        { 
            // Prevent anyone from creating a blank instance of a proxy
            // without the underlying server type 
        } 

        internal int CtorThread 
        {
            get
            {
                return _ctorThread; 
            }
            set 
            { 
                //NOTE : the assert below is correct for activated objects.
                //But for a connected object (where new XXX() does a Connect() 
                //the InternalActivate codepath may execute twice .. since
                //we would be returning the same proxy for multiple calls to
                //new XXX() & JIT would try to execute the default .ctor on
                //the returned proxy. 

                //BCLDebug.Assert(_ctorThread == 0, "ctorThread already set??"); 
                _ctorThread = value; 
            }
        } 

        // This is used when a TP is called with SyncProcessMessage
        internal static IMessage CallProcessMessage(IMessageSink ms,
                                                    IMessage reqMsg, 
                                                    ArrayWithSize proxySinks,
                                                    Thread currentThread, 
                                                    Context currentContext, 
                                                    bool bSkippingContextChain)
        { 
            // Notify Dynamic Sinks: CALL starting
            if (proxySinks != null)
            {
                DynamicPropertyHolder.NotifyDynamicSinks( 
                                            reqMsg,
                                            proxySinks, 
                                            true,   // bCliSide 
                                            true,   // bStart
                                            false); // bAsync 
            }

            bool bHasDynamicSinks = false;
            if (bSkippingContextChain) 
            {
                // this would have been done in the client context terminator sink 
                bHasDynamicSinks = 
                    currentContext.NotifyDynamicSinks(reqMsg,
                        true,   // bCliSide 
                        true,   // bStart
                        false,  // bAsync
                        true);  // bNotifyGlobals
 
                ChannelServices.NotifyProfiler(reqMsg, RemotingProfilerEvent.ClientSend);
            } 
 
            if (ms == null)
            { 
                throw new RemotingException(
                    Environment.GetResourceString(
                        "Remoting_Proxy_NoChannelSink"));
            } 

            IMessage retMsg = ms.SyncProcessMessage(reqMsg); 
 
            if (bSkippingContextChain)
            { 
                // this would have been done in the client context terminator sink
                ChannelServices.NotifyProfiler(retMsg, RemotingProfilerEvent.ClientReceive);

                if (bHasDynamicSinks) 
                {
                    currentContext.NotifyDynamicSinks( 
                        retMsg, 
                        true,   // bCliSide
                        false,   // bStart 
                        false,  // bAsync
                        true);  // bNotifyGlobals
                }
            } 

            IMethodReturnMessage mrm = retMsg as IMethodReturnMessage; 
            if (retMsg == null || mrm == null) 
            {
                throw new RemotingException( 
                    Environment.GetResourceString("Remoting_Message_BadType"));
            }

            // notify DynamicSinks: CALL returned 
            if (proxySinks != null)
            { 
                DynamicPropertyHolder.NotifyDynamicSinks( 
                                            retMsg,
                                            proxySinks, 
                                            true,   // bCliSide
                                            false,  // bStart
                                            false); // bAsync
            } 

 
            return retMsg; 
        }
 
        // Implement Invoke
        public override IMessage Invoke(IMessage reqMsg)
        {
            // Dispatch based on whether its a constructor call 
            // or a method call
 
            IConstructionCallMessage ccm = reqMsg as IConstructionCallMessage; 

            if(ccm != null) 
            {
                // Activate
                return InternalActivate(ccm);
            } 
            else
            { 
                // Handle regular method calls 

                // Check that the initialization has completed 
                if(!Initialized)
                {
                    // This covers the case where an object may call out
                    // on another object passing its "this" pointer during its 
                    // .ctor.
                    // The other object attempting to call on the this pointer 
                    // (in x-context case) would be calling on a proxy not 
                    // marked fully initialized.
                    // < 



                    // Let the original constructor thread go through but 
                    // throw for other threads.
                    if (CtorThread == Thread.CurrentThread.GetHashCode()) 
                    { 
                        ServerIdentity srvId = IdentityObject as ServerIdentity;
                        BCLDebug.Assert( 
                            srvId != null
                            &&
                            ((ServerIdentity)IdentityObject).ServerContext != null,
                            "Wrap may associate with wrong context!"); 

                        // If we are here, the server object passed itself 
                        // out to another x-context object during the .ctor 
                        // That guy is calling us back. Let us call Wrap()
                        // earlier than usual so that envoy & channel sinks 
                        // get set up!
                        // <

 

                        RemotingServices.Wrap( 
                            (ContextBoundObject) this.UnwrappedServerObject); 

                    } 
                    else
                    {
                        // Throw an exception to indicate that we are
                        // calling on a proxy while the constructor call 
                        // is still running.
                        throw new RemotingException(Environment.GetResourceString("Remoting_Proxy_InvalidCall")); 
                    } 

                } 

                // Dispatch
                int callType = Message.[....];
                Message msg = reqMsg as Message; 
                if (msg != null)
                { 
                    callType = msg.GetCallType(); 
                }
 
                return InternalInvoke((IMethodCallMessage)reqMsg, false, callType);
            }

        } // Invoke 

 
        // This is called for all remoted calls on a TP except Ctors 
        // The method called may be [....], Async or OneWay(special case of Async)
        // In the Async case we come here for both BeginInvoke & EndInvoke 
        internal virtual IMessage InternalInvoke(
            IMethodCallMessage reqMcmMsg, bool useDispatchMessage, int callType)
        {
            Message reqMsg = reqMcmMsg as Message; 
            if ((reqMsg == null) && (callType != Message.[....]))
            { 
                // Only the synchronous call type is supported for messages that 
                //   aren't of type Message.
                throw new RemotingException( 
                    Environment.GetResourceString("Remoting_Proxy_InvalidCallType"));
            }

            IMessage retMsg = null; 
            Thread currentThread = Thread.CurrentThread;
 
            // pick up call context from the thread 
            LogicalCallContext cctx = currentThread.GetLogicalCallContext();
 
            Identity idObj = IdentityObject;
            ServerIdentity serverID = idObj as ServerIdentity;
            if ((null != serverID) && idObj.IsFullyDisconnected())
            { 
                throw new ArgumentException(
                   String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Remoting_ServerObjectNotFound"), reqMcmMsg.Uri)); 
            } 

            // Short-circuit calls to Object::GetType and Object::GetHashCode 
            MethodBase mb = reqMcmMsg.MethodBase;
            if(_getTypeMethod == mb)
            {
                // Time to load the true type of the remote object.... 
                Type t = GetProxiedType();
                return new ReturnMessage(t, null, 0, cctx, reqMcmMsg); 
            } 

            if (_getHashCodeMethod == mb) 
            {
                int hashCode = idObj.GetHashCode();
                return new ReturnMessage(hashCode, null, 0, cctx, reqMcmMsg);
            } 

            // check for channel sink 
            if (idObj.ChannelSink == null) 
            {
                IMessageSink chnlSink = null; 
                IMessageSink envoySink = null;
                // If channelSink is null try to Create them again
                // the objref should be correctly fixed up at this point
                if(!idObj.ObjectRef.IsObjRefLite()) 
                {
                    RemotingServices.CreateEnvoyAndChannelSinks(null, idObj.ObjectRef, out chnlSink, out envoySink); 
                } 
                else
                { 
                    RemotingServices.CreateEnvoyAndChannelSinks(idObj.ObjURI, null, out chnlSink, out envoySink);
                }
                // Set the envoy and channel sinks in a thread safe manner
                RemotingServices.SetEnvoyAndChannelSinks(idObj, chnlSink, envoySink); 

                // If the channel sink is still null then throw 
                if(idObj.ChannelSink == null) 
                {
                    throw new RemotingException( 
                        Environment.GetResourceString("Remoting_Proxy_NoChannelSink"));
                }
            }
 
            // Set the identity in the message object
            IInternalMessage iim = (IInternalMessage)reqMcmMsg; 
            iim.IdentityObject = idObj; 

            if (null != serverID) 
            {
                Message.DebugOut("Setting serveridentity on message \n");
                iim.ServerIdentityObject = serverID;
 
            }
            else 
            { 
                // We need to set the URI only for identities that
                // are not the server identities. The uri is used to 
                // dispatch methods for objects outside the appdomain.
                // Inside the appdomain (xcontext case) we dispatch
                // by getting the server object from the server identity.
               iim.SetURI(idObj.URI); 
            }
 
            Message.DebugOut("InternalInvoke. Dispatching based on class type\n"); 
            AsyncResult ar = null;
            switch (callType) 
            {
            case Message.[....]:
                Message.DebugOut("RemotingProxy.Invoke Call: SyncProcessMsg\n");
                BCLDebug.Assert(!useDispatchMessage,"!useDispatchMessage"); 
                bool bSkipContextChain = false;
                Context currentContext = currentThread.GetCurrentContextInternal(); 
                IMessageSink nextSink = idObj.EnvoyChain; 

                // if we are in the default context, there can be no 
                // client context chain, so we can skip the intermediate
                // calls if there are no envoy sinks

                if (currentContext.IsDefaultContext) 
                {
                    if (nextSink is EnvoyTerminatorSink) 
                    { 
                        bSkipContextChain = true;
 
                        // jump directly to the channel sink
                        nextSink = idObj.ChannelSink;
                    }
                } 

                retMsg = CallProcessMessage(nextSink, 
                                            reqMcmMsg, 
                                            idObj.ProxySideDynamicSinks,
                                            currentThread, 
                                            currentContext,
                                            bSkipContextChain);

                break; 

            case Message.BeginAsync: 
            case Message.BeginAsync | Message.OneWay: 
                // For async calls we clone the call context from the thread
                // This is a limited clone (we dont deep copy the user data) 
                cctx = (LogicalCallContext) cctx.Clone();
                iim.SetCallContext(cctx);

                ar = new AsyncResult(reqMsg); 

                InternalInvokeAsync(ar, reqMsg, useDispatchMessage, callType); 
 
                Message.DebugOut("Propagate out params for BeginAsync\n");
                retMsg = new ReturnMessage(ar, null, 0, null/*cctx*/, reqMsg); 
                break;

            case Message.OneWay:
                // For async calls we clone the call context from the thread 
                // This is a limited clone (we dont deep copy the user data)
                cctx = (LogicalCallContext) cctx.Clone(); 
                iim.SetCallContext(cctx); 
                InternalInvokeAsync(null, reqMsg, useDispatchMessage, callType);
                retMsg = new ReturnMessage(null, null, 0, null/*cctx*/, reqMcmMsg); 
                break;

            case (Message.EndAsync | Message.OneWay):
                retMsg = new ReturnMessage(null, null, 0, null/*cctx*/, reqMcmMsg); 
                break;
 
            case Message.EndAsync: 
                // For endAsync, we merge back the returned callContext
                // into the thread's callContext 
                retMsg = RealProxy.EndInvokeHelper(reqMsg, true);
                break;
            }
 
            return retMsg;
        } 
 
        // This is called from InternalInvoke above when someone makes an
        // Async (or a one way) call on a TP 
        internal void InternalInvokeAsync(IMessageSink ar,  Message reqMsg,
            bool useDispatchMessage, int callType)
        {
            IMessageCtrl cc = null; 
            Identity idObj = IdentityObject;
            ServerIdentity serverID = idObj as ServerIdentity; 
            MethodCall cpyMsg= new MethodCall(reqMsg); 
            IInternalMessage iim = ((IInternalMessage)cpyMsg);
 
            // Set the identity in the message object
            iim.IdentityObject = idObj;
            if (null != serverID)
            { 
                Message.DebugOut("Setting SrvID on deser msg\n");
                iim.ServerIdentityObject = serverID; 
            } 

            if (useDispatchMessage) 
            {
                Message.DebugOut(
                    "RemotingProxy.Invoke: Calling AsyncDispatchMessage\n");
 
                BCLDebug.Assert(ar != null,"ar != null");
                BCLDebug.Assert( (callType & Message.BeginAsync) != 0, 
                                "BeginAsync flag not set!"); 

                Message.DebugOut("Calling AsynDispatchMessage \n"); 
                cc = ChannelServices.AsyncDispatchMessage(
                                        cpyMsg,
                                        ((callType & Message.OneWay) != 0)
                                        ? null : ar); 
            }
            else if (null != idObj.EnvoyChain) 
            { 
                Message.DebugOut("RemotingProxy.Invoke: Calling AsyncProcessMsg on the envoy chain\n");
 
                cc = idObj.EnvoyChain.AsyncProcessMessage(
                                        cpyMsg,
                                        ((callType & Message.OneWay) != 0)
                                        ? null : ar); 
            }
            else 
            { 
                // Channel sink cannot be null since it is the last sink in
                // the client context 
                // Assert if Invoke is called without a channel sink
                BCLDebug.Assert(false, "How did we get here?");
                throw new ExecutionEngineException(
                    Environment.GetResourceString("Remoting_Proxy_InvalidState")); 
            }
 
            if ((callType & Message.BeginAsync) != 0) 
            {
 
                if ((callType & Message.OneWay) != 0)
                {
                    ar.SyncProcessMessage(null);
                } 
            }
        } 
 
        // New method for activators.
 
        // This gets called during remoting intercepted activation when
        // JIT tries to run a constructor on a TP (which remoting gave it
        // in place of an actual uninitialized instance of the expected type)
        private IConstructionReturnMessage InternalActivate(IConstructionCallMessage ctorMsg) 
        {
            // Remember the hashcode of the constructor thread. 
            CtorThread = Thread.CurrentThread.GetHashCode(); 

            IConstructionReturnMessage ctorRetMsg = ActivationServices.Activate(this, ctorMsg); 

            // Set the flag to indicate that the object is initialized
            // Note: this assert is not valid for WKOs
            //BCLDebug.Assert(!Initialized, "Proxy marked as initialized before activation call completed"); 
            Initialized = true;
 
            return ctorRetMsg; 
        }
 
        // Invoke for case where call is in the same context as the server object
        // (This special static method is used for AsyncDelegate-s ... this is called
        // directly from the EE)
        private static void Invoke(Object NotUsed, ref MessageData msgData) 
        {
            Message m = new Message(); 
            m.InitFields(msgData); 

            Object thisPtr = m.GetThisPtr(); 
            Delegate d;
            if ((d = thisPtr as Delegate) != null)
            {
                // < 

                RemotingProxy rp = (RemotingProxy) 
                    RemotingServices.GetRealProxy(d.Target); 

                if (rp != null) 
                {
                    rp.InternalInvoke(m, true, m.GetCallType());
                }
                else 
                {
                    int callType = m.GetCallType(); 
                    AsyncResult ar; 
                    switch (callType)
                    { 
                    case Message.BeginAsync:
                    case Message.BeginAsync | Message.OneWay:
                        // pick up call context from the thread
                        m.Properties[Message.CallContextKey] = 
                            CallContext.GetLogicalCallContext().Clone();
                        ar = new AsyncResult(m); 
                        AgileAsyncWorkerItem  workItem = 
                            new AgileAsyncWorkerItem(
                                    m, 
                                    ((callType & Message.OneWay) != 0) ?
                                        null : ar, d.Target);

                        ThreadPool.QueueUserWorkItem( 
                            new WaitCallback(
                                    AgileAsyncWorkerItem.ThreadPoolCallBack), 
                            workItem); 

                        if ((callType & Message.OneWay) != 0) 
                        {
                            ar.SyncProcessMessage(null);
                        }
                        m.PropagateOutParameters(null, ar); 
                        break;
                    case (Message.EndAsync | Message.OneWay): 
                        return; 

                    case Message.EndAsync: 
                        // This will also merge back the call context
                        // onto the thread that called EndAsync
                        RealProxy.EndInvokeHelper(m, false);
                        break; 
                    default:
                        BCLDebug.Assert( 
                            false, 
                            "Should never be here. [....] delegate code for agile object ended up in remoting");
                        break; 
                    }
                }
            }
            else 
            {
                // Static invoke called with incorrect this pointer ... 
                throw new RemotingException( 
                    Environment.GetResourceString(
                        "Remoting_Default")); 
            }
        }

        internal ConstructorCallMessage ConstructorMessage 
        {
            get 
            { 
                return _ccm;
            } 

            set
            {
                _ccm = value; 
            }
        } 
 
        //
        // IRemotingTypeInfo interface 
        //

        // Obtain the fully qualified name of the type that the proxy represents
        public String TypeName 
        {
            get 
            { 
                return GetProxiedType().FullName;
            } 

            set
            {
                throw new NotSupportedException(); 
            }
        } 
 
#if FEATURE_COMINTEROP
        // interop methods 
        public override IntPtr GetCOMIUnknown(bool fIsBeingMarshalled)
        {
            IntPtr pUnk = IntPtr.Zero;
            Object otp = GetTransparentProxy(); 
            bool fIsXProcess = RemotingServices.IsObjectOutOfProcess(otp);
            if (fIsXProcess) 
            { 
                // we are in a different process
                if (fIsBeingMarshalled) 
                {
                    // we need to go to the server to get the real IUnknown
                    pUnk =  MarshalByRefObject.GetComIUnknown((MarshalByRefObject)otp);
                } 
                else
                { 
                    // create an IUnknown here 
                    pUnk =  MarshalByRefObject.GetComIUnknown((MarshalByRefObject)otp);
                } 
            }
            else
            {
                bool fIsXAppDomain = RemotingServices.IsObjectOutOfAppDomain(otp); 
                // we are in the same proces, ask the object for its IUnknown
                if (fIsXAppDomain) 
                { 
                    // do an appdomain switch
                    pUnk = ((MarshalByRefObject)otp).GetComIUnknown(fIsBeingMarshalled); 
                }
                else
                {
                    // otherwise go ahead and create a CCW here 
                    pUnk = MarshalByRefObject.GetComIUnknown((MarshalByRefObject)otp);
                } 
            } 

            return pUnk; 
        }

        public override void SetCOMIUnknown(IntPtr i)
        { 
            // for now ignore this
        } 
#endif // FEATURE_COMINTEROP 

        // Check whether we can cast the transparent proxy to the given type 
        public bool CanCastTo(Type castType, Object o)
        {
            bool fCastOK = false;
 
            // The identity should be non-null
            BCLDebug.Assert(null != IdentityObject,"null != IdentityObject"); 
 
            Message.DebugOut("CheckCast for identity " + IdentityObject.GetType());
 
            if ((castType == s_typeofObject) ||
                (castType == s_typeofMarshalByRefObject))
            {
                return true; 
            }
 
            // Get the objref of the proxy 
            ObjRef oRef = IdentityObject.ObjectRef;
 
            // If the object ref is non-null then check against the type info
            // stored in the it
            if (null != oRef)
            { 
                Object oTP = GetTransparentProxy();
 
                // Check that there is a matching type in the server object 
                // hierarchy represented in the objref
                Message.DebugOut("Calling CanCastTo for type " + castType); 
                IRemotingTypeInfo typeInfo = oRef.TypeInfo;
                if(null != typeInfo)
                {
                    fCastOK = typeInfo.CanCastTo(castType, oTP); 
                    if (!fCastOK && typeInfo.GetType()==typeof(TypeInfo) && oRef.IsWellKnown() )
                    { 
                        fCastOK = CanCastToWK(castType); 
                    }
                } 
                else
                {
                    if (oRef.IsObjRefLite())
                    { 
                        // we should do a dynamic cast across the network
                        fCastOK = MarshalByRefObject.CanCastToXmlTypeHelper(castType, (MarshalByRefObject)o); 
                    } 
                }
            } 
            // This is a well known object which does not have a backing ObjRef
            else
            {
            fCastOK = CanCastToWK(castType); 
            }
            return fCastOK; 
        } 

        // WellKnown proxies we always allow casts to interfaces, and allow 
        // casting down a single branch in the type hierarchy (both are on good
        // faith. The calls are failed on server side if a bogus cast is done)
        bool CanCastToWK(Type castType)
        { 
            Message.DebugOut( "CheckCast for well known objects and type " + castType);
            bool fCastOK = false; 
            // Check whether the type to which we want to cast is 
            // compatible with the current type
            if(castType.IsClass) 
            {
                fCastOK = GetProxiedType().IsAssignableFrom(castType);
            }
            else 
            {
                // NOTE: we are coming here also for x-context proxies 
                // when unmanaged code cannot determine if the cast is not 
                // okay <
                if (!(IdentityObject is ServerIdentity)) 
                {
                    BCLDebug.Assert(
                        IdentityObject.URI != null,
                        "Bad WellKnown ID"); 
                    // Always allow interface casts to succeed. If the
                    // interface is not supported by the well known object 
                    // then we will throw an exception when the interface 
                    // is invoked.
                    fCastOK = true; 
                }
            }

            return fCastOK; 
        }
    } 
 

    internal class AgileAsyncWorkerItem 
    {
        private IMethodCallMessage _message;
        private AsyncResult        _ar;
        private Object             _target; 

        public AgileAsyncWorkerItem(IMethodCallMessage message, AsyncResult ar, Object target) 
        { 
            _message = new MethodCall(message);
            _ar = ar; 
            _target = target;
        }

        public static void ThreadPoolCallBack(Object o) 
        {
            ((AgileAsyncWorkerItem) o).DoAsyncCall(); 
        } 

 
        public void DoAsyncCall()
        {
            (new StackBuilderSink(_target)).AsyncProcessMessage(_message, _ar);
        } 
    }
 
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// ==++== 
//
//   Copyright (c) Microsoft Corporation.  All rights reserved.
//
// ==--== 
/*============================================================
** 
** File:    RemotingProxy.cs 
**
** 
** Purpose: Defines the general purpose remoting proxy
**
**
===========================================================*/ 
namespace System.Runtime.Remoting.Proxies {
    using System.Threading; 
    using System.Runtime.Remoting.Activation; 
    using System.Runtime.Remoting.Messaging;
    using System.Runtime.Remoting.Contexts; 
    using System.Runtime.Remoting.Channels;
    using System;
    using MethodInfo = System.Reflection.MethodInfo;
    using MethodBase = System.Reflection.MethodBase; 
    using System.Globalization;
    // Remoting proxy 
    internal class RemotingProxy : RealProxy, IRemotingTypeInfo 
    {
        // Static Fields 
        private static MethodInfo _getTypeMethod = typeof(System.Object).GetMethod("GetType");
        private static MethodInfo _getHashCodeMethod = typeof(System.Object).GetMethod("GetHashCode");

        private static Type s_typeofObject = typeof(System.Object); 
        private static Type s_typeofMarshalByRefObject = typeof(System.MarshalByRefObject);
 
        //*******************WARNING****************************************** 
        // If you change the names of these fields then change the corresponding
        // names in remoting.cpp 
        //*******************************************************************
        private ConstructorCallMessage _ccm;
        private int _ctorThread;
 

        // Constructor 
        public RemotingProxy(Type serverType) 
        : base(serverType)
        { 
        }

        private RemotingProxy()
        { 
            // Prevent anyone from creating a blank instance of a proxy
            // without the underlying server type 
        } 

        internal int CtorThread 
        {
            get
            {
                return _ctorThread; 
            }
            set 
            { 
                //NOTE : the assert below is correct for activated objects.
                //But for a connected object (where new XXX() does a Connect() 
                //the InternalActivate codepath may execute twice .. since
                //we would be returning the same proxy for multiple calls to
                //new XXX() & JIT would try to execute the default .ctor on
                //the returned proxy. 

                //BCLDebug.Assert(_ctorThread == 0, "ctorThread already set??"); 
                _ctorThread = value; 
            }
        } 

        // This is used when a TP is called with SyncProcessMessage
        internal static IMessage CallProcessMessage(IMessageSink ms,
                                                    IMessage reqMsg, 
                                                    ArrayWithSize proxySinks,
                                                    Thread currentThread, 
                                                    Context currentContext, 
                                                    bool bSkippingContextChain)
        { 
            // Notify Dynamic Sinks: CALL starting
            if (proxySinks != null)
            {
                DynamicPropertyHolder.NotifyDynamicSinks( 
                                            reqMsg,
                                            proxySinks, 
                                            true,   // bCliSide 
                                            true,   // bStart
                                            false); // bAsync 
            }

            bool bHasDynamicSinks = false;
            if (bSkippingContextChain) 
            {
                // this would have been done in the client context terminator sink 
                bHasDynamicSinks = 
                    currentContext.NotifyDynamicSinks(reqMsg,
                        true,   // bCliSide 
                        true,   // bStart
                        false,  // bAsync
                        true);  // bNotifyGlobals
 
                ChannelServices.NotifyProfiler(reqMsg, RemotingProfilerEvent.ClientSend);
            } 
 
            if (ms == null)
            { 
                throw new RemotingException(
                    Environment.GetResourceString(
                        "Remoting_Proxy_NoChannelSink"));
            } 

            IMessage retMsg = ms.SyncProcessMessage(reqMsg); 
 
            if (bSkippingContextChain)
            { 
                // this would have been done in the client context terminator sink
                ChannelServices.NotifyProfiler(retMsg, RemotingProfilerEvent.ClientReceive);

                if (bHasDynamicSinks) 
                {
                    currentContext.NotifyDynamicSinks( 
                        retMsg, 
                        true,   // bCliSide
                        false,   // bStart 
                        false,  // bAsync
                        true);  // bNotifyGlobals
                }
            } 

            IMethodReturnMessage mrm = retMsg as IMethodReturnMessage; 
            if (retMsg == null || mrm == null) 
            {
                throw new RemotingException( 
                    Environment.GetResourceString("Remoting_Message_BadType"));
            }

            // notify DynamicSinks: CALL returned 
            if (proxySinks != null)
            { 
                DynamicPropertyHolder.NotifyDynamicSinks( 
                                            retMsg,
                                            proxySinks, 
                                            true,   // bCliSide
                                            false,  // bStart
                                            false); // bAsync
            } 

 
            return retMsg; 
        }
 
        // Implement Invoke
        public override IMessage Invoke(IMessage reqMsg)
        {
            // Dispatch based on whether its a constructor call 
            // or a method call
 
            IConstructionCallMessage ccm = reqMsg as IConstructionCallMessage; 

            if(ccm != null) 
            {
                // Activate
                return InternalActivate(ccm);
            } 
            else
            { 
                // Handle regular method calls 

                // Check that the initialization has completed 
                if(!Initialized)
                {
                    // This covers the case where an object may call out
                    // on another object passing its "this" pointer during its 
                    // .ctor.
                    // The other object attempting to call on the this pointer 
                    // (in x-context case) would be calling on a proxy not 
                    // marked fully initialized.
                    // < 



                    // Let the original constructor thread go through but 
                    // throw for other threads.
                    if (CtorThread == Thread.CurrentThread.GetHashCode()) 
                    { 
                        ServerIdentity srvId = IdentityObject as ServerIdentity;
                        BCLDebug.Assert( 
                            srvId != null
                            &&
                            ((ServerIdentity)IdentityObject).ServerContext != null,
                            "Wrap may associate with wrong context!"); 

                        // If we are here, the server object passed itself 
                        // out to another x-context object during the .ctor 
                        // That guy is calling us back. Let us call Wrap()
                        // earlier than usual so that envoy & channel sinks 
                        // get set up!
                        // <

 

                        RemotingServices.Wrap( 
                            (ContextBoundObject) this.UnwrappedServerObject); 

                    } 
                    else
                    {
                        // Throw an exception to indicate that we are
                        // calling on a proxy while the constructor call 
                        // is still running.
                        throw new RemotingException(Environment.GetResourceString("Remoting_Proxy_InvalidCall")); 
                    } 

                } 

                // Dispatch
                int callType = Message.[....];
                Message msg = reqMsg as Message; 
                if (msg != null)
                { 
                    callType = msg.GetCallType(); 
                }
 
                return InternalInvoke((IMethodCallMessage)reqMsg, false, callType);
            }

        } // Invoke 

 
        // This is called for all remoted calls on a TP except Ctors 
        // The method called may be [....], Async or OneWay(special case of Async)
        // In the Async case we come here for both BeginInvoke & EndInvoke 
        internal virtual IMessage InternalInvoke(
            IMethodCallMessage reqMcmMsg, bool useDispatchMessage, int callType)
        {
            Message reqMsg = reqMcmMsg as Message; 
            if ((reqMsg == null) && (callType != Message.[....]))
            { 
                // Only the synchronous call type is supported for messages that 
                //   aren't of type Message.
                throw new RemotingException( 
                    Environment.GetResourceString("Remoting_Proxy_InvalidCallType"));
            }

            IMessage retMsg = null; 
            Thread currentThread = Thread.CurrentThread;
 
            // pick up call context from the thread 
            LogicalCallContext cctx = currentThread.GetLogicalCallContext();
 
            Identity idObj = IdentityObject;
            ServerIdentity serverID = idObj as ServerIdentity;
            if ((null != serverID) && idObj.IsFullyDisconnected())
            { 
                throw new ArgumentException(
                   String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Remoting_ServerObjectNotFound"), reqMcmMsg.Uri)); 
            } 

            // Short-circuit calls to Object::GetType and Object::GetHashCode 
            MethodBase mb = reqMcmMsg.MethodBase;
            if(_getTypeMethod == mb)
            {
                // Time to load the true type of the remote object.... 
                Type t = GetProxiedType();
                return new ReturnMessage(t, null, 0, cctx, reqMcmMsg); 
            } 

            if (_getHashCodeMethod == mb) 
            {
                int hashCode = idObj.GetHashCode();
                return new ReturnMessage(hashCode, null, 0, cctx, reqMcmMsg);
            } 

            // check for channel sink 
            if (idObj.ChannelSink == null) 
            {
                IMessageSink chnlSink = null; 
                IMessageSink envoySink = null;
                // If channelSink is null try to Create them again
                // the objref should be correctly fixed up at this point
                if(!idObj.ObjectRef.IsObjRefLite()) 
                {
                    RemotingServices.CreateEnvoyAndChannelSinks(null, idObj.ObjectRef, out chnlSink, out envoySink); 
                } 
                else
                { 
                    RemotingServices.CreateEnvoyAndChannelSinks(idObj.ObjURI, null, out chnlSink, out envoySink);
                }
                // Set the envoy and channel sinks in a thread safe manner
                RemotingServices.SetEnvoyAndChannelSinks(idObj, chnlSink, envoySink); 

                // If the channel sink is still null then throw 
                if(idObj.ChannelSink == null) 
                {
                    throw new RemotingException( 
                        Environment.GetResourceString("Remoting_Proxy_NoChannelSink"));
                }
            }
 
            // Set the identity in the message object
            IInternalMessage iim = (IInternalMessage)reqMcmMsg; 
            iim.IdentityObject = idObj; 

            if (null != serverID) 
            {
                Message.DebugOut("Setting serveridentity on message \n");
                iim.ServerIdentityObject = serverID;
 
            }
            else 
            { 
                // We need to set the URI only for identities that
                // are not the server identities. The uri is used to 
                // dispatch methods for objects outside the appdomain.
                // Inside the appdomain (xcontext case) we dispatch
                // by getting the server object from the server identity.
               iim.SetURI(idObj.URI); 
            }
 
            Message.DebugOut("InternalInvoke. Dispatching based on class type\n"); 
            AsyncResult ar = null;
            switch (callType) 
            {
            case Message.[....]:
                Message.DebugOut("RemotingProxy.Invoke Call: SyncProcessMsg\n");
                BCLDebug.Assert(!useDispatchMessage,"!useDispatchMessage"); 
                bool bSkipContextChain = false;
                Context currentContext = currentThread.GetCurrentContextInternal(); 
                IMessageSink nextSink = idObj.EnvoyChain; 

                // if we are in the default context, there can be no 
                // client context chain, so we can skip the intermediate
                // calls if there are no envoy sinks

                if (currentContext.IsDefaultContext) 
                {
                    if (nextSink is EnvoyTerminatorSink) 
                    { 
                        bSkipContextChain = true;
 
                        // jump directly to the channel sink
                        nextSink = idObj.ChannelSink;
                    }
                } 

                retMsg = CallProcessMessage(nextSink, 
                                            reqMcmMsg, 
                                            idObj.ProxySideDynamicSinks,
                                            currentThread, 
                                            currentContext,
                                            bSkipContextChain);

                break; 

            case Message.BeginAsync: 
            case Message.BeginAsync | Message.OneWay: 
                // For async calls we clone the call context from the thread
                // This is a limited clone (we dont deep copy the user data) 
                cctx = (LogicalCallContext) cctx.Clone();
                iim.SetCallContext(cctx);

                ar = new AsyncResult(reqMsg); 

                InternalInvokeAsync(ar, reqMsg, useDispatchMessage, callType); 
 
                Message.DebugOut("Propagate out params for BeginAsync\n");
                retMsg = new ReturnMessage(ar, null, 0, null/*cctx*/, reqMsg); 
                break;

            case Message.OneWay:
                // For async calls we clone the call context from the thread 
                // This is a limited clone (we dont deep copy the user data)
                cctx = (LogicalCallContext) cctx.Clone(); 
                iim.SetCallContext(cctx); 
                InternalInvokeAsync(null, reqMsg, useDispatchMessage, callType);
                retMsg = new ReturnMessage(null, null, 0, null/*cctx*/, reqMcmMsg); 
                break;

            case (Message.EndAsync | Message.OneWay):
                retMsg = new ReturnMessage(null, null, 0, null/*cctx*/, reqMcmMsg); 
                break;
 
            case Message.EndAsync: 
                // For endAsync, we merge back the returned callContext
                // into the thread's callContext 
                retMsg = RealProxy.EndInvokeHelper(reqMsg, true);
                break;
            }
 
            return retMsg;
        } 
 
        // This is called from InternalInvoke above when someone makes an
        // Async (or a one way) call on a TP 
        internal void InternalInvokeAsync(IMessageSink ar,  Message reqMsg,
            bool useDispatchMessage, int callType)
        {
            IMessageCtrl cc = null; 
            Identity idObj = IdentityObject;
            ServerIdentity serverID = idObj as ServerIdentity; 
            MethodCall cpyMsg= new MethodCall(reqMsg); 
            IInternalMessage iim = ((IInternalMessage)cpyMsg);
 
            // Set the identity in the message object
            iim.IdentityObject = idObj;
            if (null != serverID)
            { 
                Message.DebugOut("Setting SrvID on deser msg\n");
                iim.ServerIdentityObject = serverID; 
            } 

            if (useDispatchMessage) 
            {
                Message.DebugOut(
                    "RemotingProxy.Invoke: Calling AsyncDispatchMessage\n");
 
                BCLDebug.Assert(ar != null,"ar != null");
                BCLDebug.Assert( (callType & Message.BeginAsync) != 0, 
                                "BeginAsync flag not set!"); 

                Message.DebugOut("Calling AsynDispatchMessage \n"); 
                cc = ChannelServices.AsyncDispatchMessage(
                                        cpyMsg,
                                        ((callType & Message.OneWay) != 0)
                                        ? null : ar); 
            }
            else if (null != idObj.EnvoyChain) 
            { 
                Message.DebugOut("RemotingProxy.Invoke: Calling AsyncProcessMsg on the envoy chain\n");
 
                cc = idObj.EnvoyChain.AsyncProcessMessage(
                                        cpyMsg,
                                        ((callType & Message.OneWay) != 0)
                                        ? null : ar); 
            }
            else 
            { 
                // Channel sink cannot be null since it is the last sink in
                // the client context 
                // Assert if Invoke is called without a channel sink
                BCLDebug.Assert(false, "How did we get here?");
                throw new ExecutionEngineException(
                    Environment.GetResourceString("Remoting_Proxy_InvalidState")); 
            }
 
            if ((callType & Message.BeginAsync) != 0) 
            {
 
                if ((callType & Message.OneWay) != 0)
                {
                    ar.SyncProcessMessage(null);
                } 
            }
        } 
 
        // New method for activators.
 
        // This gets called during remoting intercepted activation when
        // JIT tries to run a constructor on a TP (which remoting gave it
        // in place of an actual uninitialized instance of the expected type)
        private IConstructionReturnMessage InternalActivate(IConstructionCallMessage ctorMsg) 
        {
            // Remember the hashcode of the constructor thread. 
            CtorThread = Thread.CurrentThread.GetHashCode(); 

            IConstructionReturnMessage ctorRetMsg = ActivationServices.Activate(this, ctorMsg); 

            // Set the flag to indicate that the object is initialized
            // Note: this assert is not valid for WKOs
            //BCLDebug.Assert(!Initialized, "Proxy marked as initialized before activation call completed"); 
            Initialized = true;
 
            return ctorRetMsg; 
        }
 
        // Invoke for case where call is in the same context as the server object
        // (This special static method is used for AsyncDelegate-s ... this is called
        // directly from the EE)
        private static void Invoke(Object NotUsed, ref MessageData msgData) 
        {
            Message m = new Message(); 
            m.InitFields(msgData); 

            Object thisPtr = m.GetThisPtr(); 
            Delegate d;
            if ((d = thisPtr as Delegate) != null)
            {
                // < 

                RemotingProxy rp = (RemotingProxy) 
                    RemotingServices.GetRealProxy(d.Target); 

                if (rp != null) 
                {
                    rp.InternalInvoke(m, true, m.GetCallType());
                }
                else 
                {
                    int callType = m.GetCallType(); 
                    AsyncResult ar; 
                    switch (callType)
                    { 
                    case Message.BeginAsync:
                    case Message.BeginAsync | Message.OneWay:
                        // pick up call context from the thread
                        m.Properties[Message.CallContextKey] = 
                            CallContext.GetLogicalCallContext().Clone();
                        ar = new AsyncResult(m); 
                        AgileAsyncWorkerItem  workItem = 
                            new AgileAsyncWorkerItem(
                                    m, 
                                    ((callType & Message.OneWay) != 0) ?
                                        null : ar, d.Target);

                        ThreadPool.QueueUserWorkItem( 
                            new WaitCallback(
                                    AgileAsyncWorkerItem.ThreadPoolCallBack), 
                            workItem); 

                        if ((callType & Message.OneWay) != 0) 
                        {
                            ar.SyncProcessMessage(null);
                        }
                        m.PropagateOutParameters(null, ar); 
                        break;
                    case (Message.EndAsync | Message.OneWay): 
                        return; 

                    case Message.EndAsync: 
                        // This will also merge back the call context
                        // onto the thread that called EndAsync
                        RealProxy.EndInvokeHelper(m, false);
                        break; 
                    default:
                        BCLDebug.Assert( 
                            false, 
                            "Should never be here. [....] delegate code for agile object ended up in remoting");
                        break; 
                    }
                }
            }
            else 
            {
                // Static invoke called with incorrect this pointer ... 
                throw new RemotingException( 
                    Environment.GetResourceString(
                        "Remoting_Default")); 
            }
        }

        internal ConstructorCallMessage ConstructorMessage 
        {
            get 
            { 
                return _ccm;
            } 

            set
            {
                _ccm = value; 
            }
        } 
 
        //
        // IRemotingTypeInfo interface 
        //

        // Obtain the fully qualified name of the type that the proxy represents
        public String TypeName 
        {
            get 
            { 
                return GetProxiedType().FullName;
            } 

            set
            {
                throw new NotSupportedException(); 
            }
        } 
 
#if FEATURE_COMINTEROP
        // interop methods 
        public override IntPtr GetCOMIUnknown(bool fIsBeingMarshalled)
        {
            IntPtr pUnk = IntPtr.Zero;
            Object otp = GetTransparentProxy(); 
            bool fIsXProcess = RemotingServices.IsObjectOutOfProcess(otp);
            if (fIsXProcess) 
            { 
                // we are in a different process
                if (fIsBeingMarshalled) 
                {
                    // we need to go to the server to get the real IUnknown
                    pUnk =  MarshalByRefObject.GetComIUnknown((MarshalByRefObject)otp);
                } 
                else
                { 
                    // create an IUnknown here 
                    pUnk =  MarshalByRefObject.GetComIUnknown((MarshalByRefObject)otp);
                } 
            }
            else
            {
                bool fIsXAppDomain = RemotingServices.IsObjectOutOfAppDomain(otp); 
                // we are in the same proces, ask the object for its IUnknown
                if (fIsXAppDomain) 
                { 
                    // do an appdomain switch
                    pUnk = ((MarshalByRefObject)otp).GetComIUnknown(fIsBeingMarshalled); 
                }
                else
                {
                    // otherwise go ahead and create a CCW here 
                    pUnk = MarshalByRefObject.GetComIUnknown((MarshalByRefObject)otp);
                } 
            } 

            return pUnk; 
        }

        public override void SetCOMIUnknown(IntPtr i)
        { 
            // for now ignore this
        } 
#endif // FEATURE_COMINTEROP 

        // Check whether we can cast the transparent proxy to the given type 
        public bool CanCastTo(Type castType, Object o)
        {
            bool fCastOK = false;
 
            // The identity should be non-null
            BCLDebug.Assert(null != IdentityObject,"null != IdentityObject"); 
 
            Message.DebugOut("CheckCast for identity " + IdentityObject.GetType());
 
            if ((castType == s_typeofObject) ||
                (castType == s_typeofMarshalByRefObject))
            {
                return true; 
            }
 
            // Get the objref of the proxy 
            ObjRef oRef = IdentityObject.ObjectRef;
 
            // If the object ref is non-null then check against the type info
            // stored in the it
            if (null != oRef)
            { 
                Object oTP = GetTransparentProxy();
 
                // Check that there is a matching type in the server object 
                // hierarchy represented in the objref
                Message.DebugOut("Calling CanCastTo for type " + castType); 
                IRemotingTypeInfo typeInfo = oRef.TypeInfo;
                if(null != typeInfo)
                {
                    fCastOK = typeInfo.CanCastTo(castType, oTP); 
                    if (!fCastOK && typeInfo.GetType()==typeof(TypeInfo) && oRef.IsWellKnown() )
                    { 
                        fCastOK = CanCastToWK(castType); 
                    }
                } 
                else
                {
                    if (oRef.IsObjRefLite())
                    { 
                        // we should do a dynamic cast across the network
                        fCastOK = MarshalByRefObject.CanCastToXmlTypeHelper(castType, (MarshalByRefObject)o); 
                    } 
                }
            } 
            // This is a well known object which does not have a backing ObjRef
            else
            {
            fCastOK = CanCastToWK(castType); 
            }
            return fCastOK; 
        } 

        // WellKnown proxies we always allow casts to interfaces, and allow 
        // casting down a single branch in the type hierarchy (both are on good
        // faith. The calls are failed on server side if a bogus cast is done)
        bool CanCastToWK(Type castType)
        { 
            Message.DebugOut( "CheckCast for well known objects and type " + castType);
            bool fCastOK = false; 
            // Check whether the type to which we want to cast is 
            // compatible with the current type
            if(castType.IsClass) 
            {
                fCastOK = GetProxiedType().IsAssignableFrom(castType);
            }
            else 
            {
                // NOTE: we are coming here also for x-context proxies 
                // when unmanaged code cannot determine if the cast is not 
                // okay <
                if (!(IdentityObject is ServerIdentity)) 
                {
                    BCLDebug.Assert(
                        IdentityObject.URI != null,
                        "Bad WellKnown ID"); 
                    // Always allow interface casts to succeed. If the
                    // interface is not supported by the well known object 
                    // then we will throw an exception when the interface 
                    // is invoked.
                    fCastOK = true; 
                }
            }

            return fCastOK; 
        }
    } 
 

    internal class AgileAsyncWorkerItem 
    {
        private IMethodCallMessage _message;
        private AsyncResult        _ar;
        private Object             _target; 

        public AgileAsyncWorkerItem(IMethodCallMessage message, AsyncResult ar, Object target) 
        { 
            _message = new MethodCall(message);
            _ar = ar; 
            _target = target;
        }

        public static void ThreadPoolCallBack(Object o) 
        {
            ((AgileAsyncWorkerItem) o).DoAsyncCall(); 
        } 

 
        public void DoAsyncCall()
        {
            (new StackBuilderSink(_target)).AsyncProcessMessage(_message, _ar);
        } 
    }
 
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.

                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK