Context.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / clr / src / BCL / System / Runtime / Remoting / Context.cs / 1305376 / Context.cs

                            // ==++== 
//
//   Copyright (c) Microsoft Corporation.  All rights reserved.
//
// ==--== 
/*============================================================
** 
** File:     Context.cs 
**
** 
** Purpose: Remoting Context core implementation.
**
**
===========================================================*/ 
namespace System.Runtime.Remoting.Contexts {
 
    using System; 
    using System.Security;
    using System.Security.Permissions; 
    using System.Threading;
    using System.Runtime.InteropServices;
    using System.Runtime.Remoting;
    using System.Runtime.Remoting.Activation; 
    using System.Runtime.Remoting.Messaging;
    using System.Runtime.Serialization; 
    using System.Runtime.CompilerServices; 
    using System.Runtime.Versioning;
    using System.Globalization; 
    using System.Diagnostics.Contracts;
    //  CallBacks provide a facility to request execution of some code
    //  in another context.
    //  CrossContextDelegate type is defined for context call backs. 
    //  Each context has a CallBackObject which can be used to perform
    //  callbacks on the context. The delegate used to request a callback 
    //  through the CallBackObject must be of CrossContextDelegate type. 
    /// 
    [System.Runtime.InteropServices.ComVisible(true)] 
    public delegate void CrossContextDelegate();

    /// 
    // deliberately not [serializable] 
    [System.Runtime.InteropServices.ComVisible(true)]
    public class Context 
    { 
        // flags to mark the state of the context object
        // marks the context as the default context 
        internal const int CTX_DEFAULT_CONTEXT   = 0x00000001;

        // marks the context as frozen
        internal const int CTX_FROZEN                = 0x00000002; 

        // Tells the context channel that the context has properties 
        // that use the threadPool themselves. 
        // In that case, the channel does not itself use threadPool.
        // This is OFF by default 
        internal const int CTX_THREADPOOL_AWARE = 0x00000004;

        private const int GROW_BY                        = 0x8;
        private const int STATICS_BUCKET_SIZE           = 0x8; 

        private IContextProperty[] _ctxProps;    // array of name-value pairs of properties 
        private DynamicPropertyHolder _dphCtx;  // Support for Dynamic Sinks 
        private LocalDataStoreHolder _localDataStore;
        private IMessageSink _serverContextChain; 
        private IMessageSink _clientContextChain;
        private AppDomain _appDomain;       // AppDomain property of the context
        private Object[] _ctxStatics;       // Holder for context statics
 
        //**********************
        // This needs to be the first NON-OBJECT field! 
        private IntPtr _internalContext; // address of the VM context object! 
        //**********************
 
        // at this point we just differentiate contexts based on context ID
        private int _ctxID;
        private int _ctxFlags;
        private int _numCtxProps;   // current count of properties 

        // Context statics stuff 
        private int _ctxStaticsCurrentBucket; 
        private int _ctxStaticsFreeIndex;
 
        // Support for dynamic properties.
        private static DynamicPropertyHolder _dphGlobal = new DynamicPropertyHolder();

        // Support for Context Local Storage 
        private static LocalDataStoreMgr _localDataStoreMgr = new LocalDataStoreMgr();
 
        // ContextID counter (for public context id) 
        private static int _ctxIDCounter = 0;
        // < 


        /// 
        [System.Security.SecurityCritical]  // auto-generated_required 
        public Context()
            : this(0) 
        { 
        }
 
        [System.Security.SecurityCritical]  // auto-generated
        private Context(int flags) {

            _ctxFlags = flags; 
            if ((_ctxFlags & CTX_DEFAULT_CONTEXT) != 0)
            { 
                _ctxID = 0;     // ID 0 == default context 
            }
            else 
            {
                _ctxID = Interlocked.Increment(ref _ctxIDCounter);
            }
 
            // Every context inherits the appdomain level properties
            // Get the properties for the appdomain and add it to 
            // this context. 
            DomainSpecificRemotingData data = Thread.GetDomain().RemotingData;
            if(null != data) 
            {
                IContextProperty[] ctxProps = data.AppDomainContextProperties;
                if(null != ctxProps)
                { 
                    for(int i = 0; i < ctxProps.Length; i++)
                    { 
                        SetProperty(ctxProps[i]); 
                    }
                } 
            }

            // Freeze the default context now
            if ((_ctxFlags & CTX_DEFAULT_CONTEXT) != 0) 
            {
                this.Freeze(); 
            } 
            // This call will set up the cycles between the VM & managed context
            // It will also set the managed context's AppDomain property to 
            // the current AppDomain.Will also publish ifthe default ctx, so should be
            // in the very end
            SetupInternalContext((_ctxFlags&CTX_DEFAULT_CONTEXT) == CTX_DEFAULT_CONTEXT);
 
            Message.DebugOut("Creating Context with ID " + _ctxID + " and flags " + flags + " " + Environment.NewLine);
        } 
 
        [System.Security.SecurityCritical]  // auto-generated
        [ResourceExposure(ResourceScope.None)] 
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        private extern void SetupInternalContext(bool bDefault);

    ///  
        [System.Security.SecuritySafeCritical]  // auto-generated
        ~Context() 
        { 
            // We clean up the backing objects only for the non-default
            // contexts. For default contexts these are cleaned up during 
            // AppDomain shutdown.
            if (_internalContext != IntPtr.Zero && (_ctxFlags & CTX_DEFAULT_CONTEXT) == 0)
            {
                CleanupInternalContext(); 
            }
        } 
 
        [System.Security.SecurityCritical]  // auto-generated
        [ResourceExposure(ResourceScope.None)] 
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        private extern void CleanupInternalContext();

        ///  
        public virtual Int32 ContextID
        { 
            [System.Security.SecurityCritical]  // auto-generated_required 
            get
            { 
                return _ctxID;
            }
        }
 
        internal virtual IntPtr InternalContextID
        { 
            get 
            {
                return _internalContext; 
            }
        }

        internal virtual AppDomain AppDomain 
        {
            get {return _appDomain;} 
        } 

        internal bool IsDefaultContext 
        {
            get { return _ctxID == 0; }
        }
 
        /// 
        public static Context DefaultContext 
        { 
            [System.Security.SecurityCritical]  // auto-generated_required
            get 
            {
                return Thread.GetDomain().GetDefaultContext();
            }
        } 

        [System.Security.SecurityCritical]  // auto-generated 
        internal static Context CreateDefaultContext() 
        {
            return new Context(CTX_DEFAULT_CONTEXT); 
        }

        /// 
        [System.Security.SecurityCritical]  // auto-generated_required 
        public virtual IContextProperty GetProperty(String name)
        { 
            if (_ctxProps == null || name == null) 
            {
                return null; 
            }
            IContextProperty prop = null;
            for (int i=0; i<_numCtxProps; i++)
            { 
                if (_ctxProps[i].Name.Equals(name))
                { 
                    prop = _ctxProps[i]; 
                    break;
                } 
            }
            return prop;
        }
 
        /// 
        [System.Security.SecurityCritical]  // auto-generated_required 
        public virtual void SetProperty(IContextProperty prop) 
        {
            // We do not let people add properties to the default context. 
            /* We allow appdomain level properties to be added to the default context
            if ((_ctxFlags & CTX_DEFAULT_CONTEXT) != 0)
            {
                throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_AddContextFrozen")); 
            }
            */ 
 
            if (prop == null || prop.Name == null)
            { 
                throw new ArgumentNullException((prop==null) ? "prop" : "property name");
            }
            Contract.EndContractBlock();
 
            if ((_ctxFlags & CTX_FROZEN) != 0)
            { 
                throw new InvalidOperationException( 
                    Environment.GetResourceString("InvalidOperation_AddContextFrozen"));
            } 

            lock (this)
            {
                // Check if we have a property by this name 
                CheckPropertyNameClash(prop.Name, _ctxProps, _numCtxProps);
 
                // check if we need to grow the array. 
                if (_ctxProps == null || _numCtxProps == _ctxProps.Length)
                { 
                    _ctxProps = GrowPropertiesArray(_ctxProps);
                }
                // now add the property
                _ctxProps[_numCtxProps++] = prop; 
            }
        } 
 
        [System.Security.SecurityCritical]  // auto-generated
        internal virtual void  InternalFreeze() 
        {
            _ctxFlags |= CTX_FROZEN;
            // From this point on attempts to add properties will throw
            // So we don't need to take a lock. 
            for (int i=0; i<_numCtxProps; i++)
            { 
                _ctxProps[i].Freeze(this); 
            }
 
        }
        /// 
        [System.Security.SecurityCritical]  // auto-generated_required
        public virtual void Freeze() 
        {
            lock(this) { 
                if ((_ctxFlags & CTX_FROZEN) != 0) 
                {
                    throw new InvalidOperationException( 
                        Environment.GetResourceString(
                            "InvalidOperation_ContextAlreadyFrozen"));
                }
                InternalFreeze(); 
            }
        } 
 
        internal virtual void SetThreadPoolAware()
        { 
            // Cannot turn off ThreadPool support for the default context
            Contract.Assert(
                (_ctxFlags & CTX_DEFAULT_CONTEXT) == 0,
                "This operation is not allowed on the default context!"); 
            _ctxFlags |= CTX_THREADPOOL_AWARE;
        } 
 
        internal virtual bool IsThreadPoolAware
        { 
            get { return (_ctxFlags & CTX_THREADPOOL_AWARE) == CTX_THREADPOOL_AWARE;}
        }

        ///  
        public virtual IContextProperty[] ContextProperties
        { 
            // we return a copy of the current set of properties 
            // the user may iterate from 0 to array.length on it.
            [System.Security.SecurityCritical]  // auto-generated_required 
            get
            {
                if (_ctxProps == null)
                { 
                    return null;
                } 
                lock (this) 
                {
                    IContextProperty[] retProps = new IContextProperty[_numCtxProps]; 
                    Array.Copy(_ctxProps, retProps, _numCtxProps);
                    return retProps;
                }
            } 
        }
 
        [System.Security.SecurityCritical]  // auto-generated 
        internal static void CheckPropertyNameClash(String name, IContextProperty[] props, int count)
        { 
            for (int i=0; i 0) 
                {
                    // see if this property wants to contribute a ServerContextSink
                    // we have to start chaining in the reverse order
                    prop = _ctxProps[iSink]; 
                    IContributeServerContextSink sink = prop as IContributeServerContextSink;
                    if (null != sink ) 
                    { 
                        // yes, chain the sink ahead of the chain of sinks constructed so far.
                        newServerContextChain = sink.GetServerContextSink( newServerContextChain); 
                        if (newServerContextChain == null)
                        {
                            throw new RemotingException(
                                Environment.GetResourceString( 
                                    "Remoting_Contexts_BadProperty"));
                        } 
                    } 
                }
                lock (this) 
                {
                    if (_serverContextChain == null)
                    {
                        _serverContextChain = newServerContextChain; 
                    }
                } 
            } 
            return _serverContextChain;
        } 

        [System.Security.SecurityCritical]  // auto-generated
        internal virtual IMessageSink GetClientContextChain()
        { 
            Message.DebugOut("Context::GetClientContextChain: IN _ctxID =" + _ctxID + Environment.NewLine);
            if (_clientContextChain == null) 
            { 
                Message.DebugOut("Context::GetClientContextChain: _clientContextChain == null, creating chain" + Environment.NewLine);
                // a bare chain would have just this one sink. 
                IMessageSink newClientContextChain = ClientContextTerminatorSink.MessageSink;

                // now loop over properties to add some real sinks.
                // Note that for the client chain we go through the properties 
                // in the reverse order as compared to the server chain.
                // Thus if a lock was taken as the last action of an incoming 
                // call, it is released as the first action of an outgoing call. 
                Object prop = null;
                int iSink = 0; 
                while (iSink < _numCtxProps)
                {
                    Message.DebugOut("Context::GetClientContextChain: checking property " +
                                     _ctxProps[iSink].Name + Environment.NewLine); 
                    // see if this property wants to contribute a ClientContextSink
                    // we have to start chaining in the reverse order 
                    prop = _ctxProps[iSink]; 
                    IContributeClientContextSink sink = prop as IContributeClientContextSink;
                    if (null != sink) 
                    {
                        Message.DebugOut("Context::GetClientContextChain: calling GetClientContextSink on " +
                                         _ctxProps[iSink].Name + Environment.NewLine);
                        // yes, chain the sink ahead of the chain of sinks constructed so far. 
                        newClientContextChain = sink.GetClientContextSink(newClientContextChain);
                        if (newClientContextChain == null) 
                        { 
                            throw new RemotingException(
                                Environment.GetResourceString( 
                                    "Remoting_Contexts_BadProperty"));
                        }
                    }
                    iSink++; 
                }
                // now check if we ----d and set appropriately 
                lock (this) 
                {
                    if (_clientContextChain==null) 
                    {
                        _clientContextChain = newClientContextChain;
                    }
                    // else the chain we created should get GC-ed. 
                }
            } 
            return _clientContextChain; 
        }
 
        [System.Security.SecurityCritical]  // auto-generated
        internal virtual IMessageSink CreateServerObjectChain(MarshalByRefObject serverObj)
        {
            // a bare chain would just be the dispatcher sink 
            IMessageSink serverObjectChain = new ServerObjectTerminatorSink(serverObj);
 
            // now loop over properties to add some real sinks. 
            Object prop = null;
            int iSink = _numCtxProps; 
            while (iSink-- > 0)
            {
                // see if this property wants to contribute a ServerObjectSink
                // we have to start chaining in the reverse order 
                prop = _ctxProps[iSink];
                IContributeObjectSink sink = prop as IContributeObjectSink; 
                if (null != sink) 
                {
                    // yes, chain the sink ahead of the chain of sinks constructed so far. 
                    serverObjectChain =  sink.GetObjectSink( serverObj, serverObjectChain);
                    if (serverObjectChain == null)
                    {
                            throw new RemotingException( 
                                Environment.GetResourceString(
                                    "Remoting_Contexts_BadProperty")); 
                    } 
                }
            } 
            return serverObjectChain;
        }

        [System.Security.SecurityCritical]  // auto-generated 
        internal virtual IMessageSink CreateEnvoyChain(MarshalByRefObject objectOrProxy)
        { 
            // a bare chain would just be the dispatcher sink 
            IMessageSink envoyChain = EnvoyTerminatorSink.MessageSink;
 
            // now loop over properties to add some real sinks.
            // Note: the sinks in the envoy chain should be in mirror image
            // order relative to sinks on the server side
            Object prop = null; 
            int iSink = 0;
 
            MarshalByRefObject exposedObj = objectOrProxy; 

            while (iSink < _numCtxProps) 
            {
                // see if this property wants to contribute a ClientContextSink
                // we have to start chaining in the reverse order
                prop = _ctxProps[iSink]; 
                IContributeEnvoySink sink = prop as IContributeEnvoySink;
                if (null != sink) 
                { 
                    // yes, chain the sink ahead of the chain of sinks constructed so far.
                    envoyChain = sink.GetEnvoySink(exposedObj, envoyChain); 
                    if (envoyChain == null)
                    {
                        throw new RemotingException(
                            Environment.GetResourceString( 
                                "Remoting_Contexts_BadProperty"));
                    } 
                } 
                iSink++;
            } 
            return envoyChain;
        }

 
        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        //~~~~~~~~~~~~~~~~~~~ Activation Support ~~~~~~~~~~~~~~~~~~~~~~~~ 
        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
        [System.Security.SecurityCritical]  // auto-generated
        internal IMessage NotifyActivatorProperties( 
            IMessage msg, bool bServerSide)
        {
            Contract.Assert( (msg is IConstructionCallMessage)
                                || (msg is IConstructionReturnMessage), 
                            "Bad activation msg type");
            Contract.Assert( !((msg is IConstructionCallMessage) && 
                                (msg is IConstructionReturnMessage)), 
                            "Activation message cannot be both call & return type");
 
            Contract.Assert((_ctxFlags & CTX_FROZEN) == CTX_FROZEN,
                            "ServerContext not frozen during activation!");

 
            // Any exception thrown by the notifications is caught and
            // folded into a return message to return to the caller. 
            IMessage errMsg = null; 

            try 
            {
                // Since the context is frozen the properties array is in
                // effect read-only!
                int iProp = _numCtxProps; 
                Object prop = null;
 
                while (iProp-- != 0) 
                {
                    // see if this property is interested in Activation 
                    prop = _ctxProps[iProp];
                    IContextPropertyActivator activator = prop as IContextPropertyActivator;
                    if (null != activator)
                    { 
                        // yes, notify as appropriate
                        IConstructionCallMessage ccm = msg as IConstructionCallMessage; 
                        if (null != ccm) 
                        {
                            // IConsructionCallMessage on its way forward 
                            if (!bServerSide)
                            {
                                // activation starting at client side
                                activator.CollectFromClientContext(ccm); 
                            }
                            else 
                            { 
                                // activation starting at server side
                                // 
                                activator.DeliverClientContextToServerContext(ccm);
                            }
                        }
                        else 
                        {
                            // IConstructionReturnMessage on its way back 
                            if (bServerSide) 
                            {
                                // activation returning from server side 
                                activator.CollectFromServerContext((IConstructionReturnMessage)msg);
                            }
                            else
                            { 
                                // activation back at client side
                                // < 
                                activator.DeliverServerContextToClientContext((IConstructionReturnMessage)msg); 
                            }
                        } 
                    }
                }
            }
            catch (Exception e) 
            {
                IMethodCallMessage mcm = null; 
                if (msg is IConstructionCallMessage) 
                {
                    mcm = (IMethodCallMessage) msg; 
                }
                else
                {
                    mcm = new ErrorMessage(); 
                }
                errMsg = new ReturnMessage(e, mcm); 
                if (msg != null) 
                {
                    ((ReturnMessage)errMsg).SetLogicalCallContext( 
                            (LogicalCallContext)
                            msg.Properties[Message.CallContextKey]);
                }
            } 
            return errMsg;
        } 
 
    /// 
        public override String ToString() 
        {
            return    "ContextID: " + _ctxID;
        }
 
        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        //~~~~~~~~~~~~~~~~~~~ Transition Support ~~~~~~~~~~~~~~~~~~~~~~~~ 
        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

        // This is the simple cross-context call back function invoke on 
        // the context to do a call-back in.
        /// 
        [System.Security.SecurityCritical]  // auto-generated_required
        public void DoCallBack(CrossContextDelegate deleg) 
        {
            /*DBG Console.WriteLine("public DoCallBack: targetCtx: " 
            + Int32.Format(this.InternalContextID,"x")); DBG*/ 

            if (deleg == null) 
            {
                throw new ArgumentNullException("deleg");
            }
            Contract.EndContractBlock(); 

            if ((_ctxFlags & CTX_FROZEN) == 0) 
            { 
                throw new RemotingException(
                    Environment.GetResourceString( 
                        "Remoting_Contexts_ContextNotFrozenForCallBack"));
            }

            Context currCtx = Thread.CurrentContext; 
            if (currCtx == this)
            { 
                // We are already in the target context, just execute deleg 
                // NOTE: If in the future we decide to leave the context
                // and reenter it for this case we will need to change 
                // Context::RequestCallBack method in VM also!
                deleg();
            }
            else 
            {
                // We pass 0 for target domain ID for x-context case. 
                currCtx.DoCallBackGeneric(this.InternalContextID, deleg); 
                GC.KeepAlive(this);
            } 
        }

        // This is called when EE needs to do a transition and execute some
        // code. Before calling, EE determines if this is a x-domain case. 
        // targetDomainID will be 0 if it is a simple x-context call.
        //< 
        [System.Security.SecurityCritical]  // auto-generated 
        internal static void DoCallBackFromEE(
            IntPtr targetCtxID, IntPtr privateData, int targetDomainID) 
        {
            Contract.Assert(targetCtxID != IntPtr.Zero, "Bad transition context");

            /*DBG Console.WriteLine("private DoCallBackFromEE: targetCtx: " 
            + Int32.Format(targetCtxID,"x")
            + " PvtData: " + Int32.Format(privateData,"x"));DBG*/ 
 
            if (targetDomainID == 0)
            { 
                CallBackHelper cb = new CallBackHelper(
                                            privateData,
                                            true /*fromEE*/,
                                            targetDomainID); 
                CrossContextDelegate ctxDel = new CrossContextDelegate(cb.Func);
                Thread.CurrentContext.DoCallBackGeneric(targetCtxID, ctxDel); 
            } 
            else
            { 
                // for x-appdomain calls, we can't pass a delegate since that
                //   would require us to deserialize it on the other side which
                //   is not allowed for non-public methods.
                TransitionCall msgCall = new TransitionCall(targetCtxID, privateData, targetDomainID); 

                Message.PropagateCallContextFromThreadToMessage(msgCall); 
                //DBG Console.WriteLine("CallBackGeneric starting!"); 
                IMessage retMsg = Thread.CurrentContext.GetClientContextChain().SyncProcessMessage(msgCall);
                Message.PropagateCallContextFromMessageToThread(retMsg); 

                IMethodReturnMessage msg = retMsg as IMethodReturnMessage;
                if (null != msg)
                { 
                    if (msg.Exception != null)
                        throw msg.Exception; 
                } 
            }
        } // DoCallBackFromEE 

                // This is called by both the call back functions above.
        [System.Security.SecurityCritical]  // auto-generated
        internal void DoCallBackGeneric( 
            IntPtr targetCtxID, CrossContextDelegate deleg)
        { 
            TransitionCall msgCall = new TransitionCall(targetCtxID, deleg); 

            Message.PropagateCallContextFromThreadToMessage(msgCall); 
            //DBG Console.WriteLine("CallBackGeneric starting!");
            IMessage retMsg = this.GetClientContextChain().SyncProcessMessage(msgCall);
            if (null != retMsg)
            { 
                Message.PropagateCallContextFromMessageToThread(retMsg);
            } 
 
            IMethodReturnMessage msg = retMsg as IMethodReturnMessage;
            if (null != msg) 
            {
                if (msg.Exception != null)
                    throw msg.Exception;
            } 
            //DBG Console.WriteLine("CallBackGeneric finished!");
        } 
 
        // This is the E-Call that we route the EE-CallBack request to
        [System.Security.SecurityCritical]  // auto-generated 
        [ResourceExposure(ResourceScope.None)]
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        internal static extern void ExecuteCallBackInEE(IntPtr privateData);
 
        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        //~~~~~~~~~~~~~~~~~~~~ Context Local Store  ~~~~~~~~~~~~~~~~~~~~ 
        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

        private LocalDataStore MyLocalStore 
        {
            get
            {
                if (_localDataStore == null) 
                {
                    // It's OK to lock the manager here because it is going to lock 
                    // itself anyway. 
                    lock (_localDataStoreMgr)
                    { 
                        if (_localDataStore == null)
                        {
                            // The local store has not yet been created for this thread.
                            _localDataStore = _localDataStoreMgr.CreateLocalDataStore(); 
                        }
                    } 
                } 
                return _localDataStore.Store;
            } 
        }

        //  All of these are exact shadows of corresponding ThreadLocalStore
        //  APIs. 
        /// 
       [System.Security.SecurityCritical]  // auto-generated_required 
        public static LocalDataStoreSlot AllocateDataSlot() 
        {
            return _localDataStoreMgr.AllocateDataSlot(); 
        }
        /// 
        [System.Security.SecurityCritical]  // auto-generated_required
        public static LocalDataStoreSlot AllocateNamedDataSlot(String name) 
        {
            return _localDataStoreMgr.AllocateNamedDataSlot(name); 
        } 
        /// 
        [System.Security.SecurityCritical]  // auto-generated_required 
        public static LocalDataStoreSlot GetNamedDataSlot(String name)
        {
            return _localDataStoreMgr.GetNamedDataSlot(name);
        } 
        /// 
        [System.Security.SecurityCritical]  // auto-generated_required 
        public static void FreeNamedDataSlot(String name) 
        {
            _localDataStoreMgr.FreeNamedDataSlot(name); 
        }

        /// 
        [System.Security.SecurityCritical]  // auto-generated_required 
        public static void SetData(LocalDataStoreSlot slot, Object data)
        { 
                        Thread.CurrentContext.MyLocalStore.SetData(slot, data); 
        }
 
        /// 
        [System.Security.SecurityCritical]  // auto-generated_required
        public static Object GetData(LocalDataStoreSlot slot)
        { 
            return Thread.CurrentContext.MyLocalStore.GetData(slot);
        } 
 
        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        //~~~~~~~~~~~~~~~~~~~~ Context Statics ~~~~~~~~~~~~~~~~~~~~~~~~~~ 
        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        private int ReserveSlot()
        {
            // This will be called with the context crst held so we 
            // don't take a lock here)
            if (_ctxStatics == null) 
            { 
                // allocate the first bucket
                _ctxStatics = new Object[STATICS_BUCKET_SIZE]; 
                // set next bucket field to null
                _ctxStatics[0] = null;
                _ctxStaticsFreeIndex = 1;
                _ctxStaticsCurrentBucket = 0; 
            }
 
            // See if we have to allocate a new bucket 
            if (_ctxStaticsFreeIndex == STATICS_BUCKET_SIZE)
            { 
                Object[] newBucket = new Object[STATICS_BUCKET_SIZE];

                // walk the chain to locate the last bucket
                Object[] bucket = _ctxStatics; 
                while (bucket[0] != null)
                { 
                    bucket = (Object[]) bucket[0]; 
                }
                // chain in the new bucket 
                bucket[0] = newBucket;
                _ctxStaticsFreeIndex = 1;
                _ctxStaticsCurrentBucket++;
            } 

            // bucket# in highWord, index in lowWord 
            return _ctxStaticsFreeIndex++|_ctxStaticsCurrentBucket<<16; 
        }
        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
        //~~~~~~~~~~~~~~~~~~~~ End Context Statics ~~~~~~~~~~~~~~~~~~~~~~
        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
        //~~~~~~~~~~~~~~~~~~~~ Dynamic Sink Support  ~~~~~~~~~~~~~~~~~~~~
        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
        //   This allows people to register a property implementing IContributeDynamicSink 
        //   with the remoting service. Based on the obj and ctx parameters, the property
        //   is asked to contribute a sink that is placed at some location in the path of 
        //   remoting calls.
        //   The property may be unregistered, which implies that the sink will be dropped
        //   for subsequent remoting calls.
        //   If multiple properties are registered, their sinks may be called in an 
        //   arbitrary order which may change between calls.
        // 
        //   If obj is non null then: 
        //       - if it is a proxy, all calls made on the proxy are intercepted
    //       - if it is a real object, all calls on the object are intercepted 
    //       - the ctx argument must be null
    //   If ctx is non-null then:
    //       - the obj argument must be null
    //       - all calls entering and leaving the context are intercepted 
    //   If both ctx and obj are null then:
    //       - all calls entering and leaving all contexts are intercepted 
    // 
    /// 
        [System.Security.SecuritySafeCritical]  // auto-generated 
        [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.Infrastructure)]
        public static bool RegisterDynamicProperty(IDynamicProperty prop, ContextBoundObject obj, Context ctx)
        {
            bool fRegistered = false; 

            if (prop == null || prop.Name == null || !(prop is IContributeDynamicSink)) 
            { 
                throw new ArgumentNullException("prop");
            } 
            if (obj != null && ctx != null)
            {
                // Exactly one of these is allowed to be non-null.
                throw new ArgumentException(Environment.GetResourceString("Argument_NonNullObjAndCtx")); 
            }
            if (obj != null) 
            { 
                // ctx is ignored and must be null.
                fRegistered = IdentityHolder.AddDynamicProperty(obj, prop); 
            }
            else
            {
                // ctx may or may not be null 
                fRegistered = Context.AddDynamicProperty(ctx, prop);
            } 
 
            return fRegistered;
        } 

    /// 
        [System.Security.SecuritySafeCritical]  // auto-generated
        [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.Infrastructure)] 
        public static bool UnregisterDynamicProperty(String name, ContextBoundObject obj, Context ctx)
        { 
            // name, obj, ctx arguments should be exactly the same as a previous 
            // RegisterDynamicProperty call
            if (name == null) 
            {
                throw new ArgumentNullException("name");
            }
            if (obj != null && ctx != null) 
            {
                throw new ArgumentException(Environment.GetResourceString("Argument_NonNullObjAndCtx")); 
            } 
            Contract.EndContractBlock();
 
            bool fUnregister = false;

            if (obj != null)
            { 
                // ctx is ignored and must be null.
                fUnregister = IdentityHolder.RemoveDynamicProperty(obj, name); 
            } 
            else
            { 
                // ctx may or may not be null
                fUnregister = Context.RemoveDynamicProperty(ctx, name);
            }
 
            return fUnregister;
        } 
 
        /*
         *  Support for dynamic sinks at context level 
         *
         */
        [System.Security.SecurityCritical]  // auto-generated
        internal static bool AddDynamicProperty(Context ctx, IDynamicProperty prop) 
        {
            // Check if we have a property by this name 
            if (ctx != null) 
            {
                return ctx.AddPerContextDynamicProperty(prop); 
            }
            else
            {
                // We have to add a sink that should fire for all contexts 
                return AddGlobalDynamicProperty(prop);
            } 
        } 

        [System.Security.SecurityCritical]  // auto-generated 
        private bool AddPerContextDynamicProperty(IDynamicProperty prop)
        {
            if (_dphCtx == null)
            { 
                DynamicPropertyHolder dph = new DynamicPropertyHolder();
                lock (this) 
                { 
                    if (_dphCtx == null)
                    { 
                        _dphCtx = dph;
                    }
                }
            } 
            return _dphCtx.AddDynamicProperty(prop);
        } 
 
        [System.Security.SecurityCritical]  // auto-generated
        private static bool AddGlobalDynamicProperty(IDynamicProperty prop) 
        {
            return _dphGlobal.AddDynamicProperty(prop);
        }
 
        [System.Security.SecurityCritical]  // auto-generated
        internal static bool RemoveDynamicProperty(Context ctx, String name) 
        { 
            if (ctx != null)
            { 
                return ctx.RemovePerContextDynamicProperty(name);
            }
            else
            { 
                // We have to remove a global property
                return RemoveGlobalDynamicProperty(name); 
            } 
        }
 
        [System.Security.SecurityCritical]  // auto-generated
        private bool RemovePerContextDynamicProperty(String name)
        {
            // We have to remove a property for this context 
            if (_dphCtx == null)
            { 
                throw new RemotingException( 
                    String.Format(
                        CultureInfo.CurrentCulture, Environment.GetResourceString("Remoting_Contexts_NoProperty"), 
                        name
                        ));
            }
            return _dphCtx.RemoveDynamicProperty(name); 
        }
 
        [System.Security.SecurityCritical]  // auto-generated 
        private static bool RemoveGlobalDynamicProperty(String name)
        { 
            return _dphGlobal.RemoveDynamicProperty(name);
        }

        /* 
         *  Returns an array of context specific dynamic properties
         *  registered for this context. The number of such properties 
         *  is designated by length of the returned array. 
         */
        internal virtual IDynamicProperty[] PerContextDynamicProperties 
        {
            get
            {
                if (_dphCtx == null) 
                {
                    return null; 
                } 
                else
                { 
                    return _dphCtx.DynamicProperties;
                }
            }
        } 

        /* 
         *  Returns an array of global dynamic properties 
         *  registered (for all contexts). The number of such properties
         *  is designated by length of the returned array. 
         */
        internal static ArrayWithSize GlobalDynamicSinks
        {
            [System.Security.SecurityCritical]  // auto-generated 
            get
            { 
                return _dphGlobal.DynamicSinks; 
            }
        } 

        internal virtual ArrayWithSize DynamicSinks
        {
            [System.Security.SecurityCritical]  // auto-generated 
            get
            { 
                if (_dphCtx == null) 
                {
                    return null; 
                }
                else
                {
                    return _dphCtx.DynamicSinks; 
                }
            } 
        } 

        [System.Security.SecurityCritical]  // auto-generated 
        internal virtual bool NotifyDynamicSinks(
            IMessage msg,
            bool bCliSide,
            bool bStart, 
            bool bAsync,
            bool bNotifyGlobals) 
        { 
            bool bHasDynamicSinks = false;
 
            if (bNotifyGlobals && (_dphGlobal.DynamicProperties != null))
            {
                ArrayWithSize globalSinks = GlobalDynamicSinks;
                if (globalSinks != null) 
                {
                    DynamicPropertyHolder.NotifyDynamicSinks( 
                                    msg, 
                                    globalSinks,
                                    bCliSide, 
                                    bStart,
                                    bAsync);
                    bHasDynamicSinks = true;
                } 
            }
 
            ArrayWithSize perCtxSinks = DynamicSinks; 
            if (perCtxSinks != null)
            { 
                DynamicPropertyHolder.NotifyDynamicSinks(
                                    msg,
                                    perCtxSinks,
                                    bCliSide, 
                                    bStart,
                                    bAsync); 
                bHasDynamicSinks = true; 
            }
 
            return bHasDynamicSinks;
        } // NotifyDynamicSinks

        //******************** END: Dynamic Sink Support ******************** 
    }
 
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
    //~~~~~~~~~~~~~~~~~~~ More Transition Support ~~~~~~~~~~~~~~~~~~~
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
    // This class is used as the backing object that implements a delegate
    // function to be used for internal call-backs. The delegate type must
    // be CrossContextDelegate (void Func(void) below) since we are using
    // the DoCallBackGeneric also as the underlying mechanism for the 
    // exposed cross-context callbacks.
    [Serializable] 
    internal class CallBackHelper 
    {
        // Some flag definitions 
        internal const int RequestedFromEE = 0x00000001;   // callBack from EE
        internal const int XDomainTransition= 0x00000100;  // going x-domain

        internal bool IsEERequested 
        {
            get {return (_flags&RequestedFromEE)==RequestedFromEE;} 
            set {if (value) {_flags |= RequestedFromEE;}} 
        }
 
        internal bool IsCrossDomain
        {
            set {if (value) {_flags |= XDomainTransition;}}
        } 

        int _flags; 
        IntPtr _privateData; 

        internal CallBackHelper(IntPtr privateData, bool bFromEE, int targetDomainID) 
        {
            this.IsEERequested = bFromEE;
            this.IsCrossDomain = (targetDomainID!=0);
            _privateData = privateData; 
        }
 
        [System.Security.SecurityCritical]  // auto-generated 
        internal void Func()
        { 
            /*DBG Console.WriteLine("DelegHelper::Func CTX:"
            + Int32.Format(Thread.CurrentContext.InternalContextID,"x")
            +Environment.NewLine + "DMN: " + Int32.Format(Thread.GetDomainID(),"x")); DBG*/
            if (IsEERequested) 
            {
                //DBG Console.WriteLine("Executing EE callback "); 
 
                // EE requested this call back, call EE with its private data
                Context.ExecuteCallBackInEE(_privateData); 

                //DBG Console.WriteLine("Execute CallBackInEE returned: " + Int32.Format(_retVal,"x"));
            }
            else 
            {
                //DBG Console.WriteLine("Executing non-EE internal callback"); 
            } 
        }
    }       // class CallBackHelper 
}       //nameSpace Remoting

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// ==++== 
//
//   Copyright (c) Microsoft Corporation.  All rights reserved.
//
// ==--== 
/*============================================================
** 
** File:     Context.cs 
**
** 
** Purpose: Remoting Context core implementation.
**
**
===========================================================*/ 
namespace System.Runtime.Remoting.Contexts {
 
    using System; 
    using System.Security;
    using System.Security.Permissions; 
    using System.Threading;
    using System.Runtime.InteropServices;
    using System.Runtime.Remoting;
    using System.Runtime.Remoting.Activation; 
    using System.Runtime.Remoting.Messaging;
    using System.Runtime.Serialization; 
    using System.Runtime.CompilerServices; 
    using System.Runtime.Versioning;
    using System.Globalization; 
    using System.Diagnostics.Contracts;
    //  CallBacks provide a facility to request execution of some code
    //  in another context.
    //  CrossContextDelegate type is defined for context call backs. 
    //  Each context has a CallBackObject which can be used to perform
    //  callbacks on the context. The delegate used to request a callback 
    //  through the CallBackObject must be of CrossContextDelegate type. 
    /// 
    [System.Runtime.InteropServices.ComVisible(true)] 
    public delegate void CrossContextDelegate();

    /// 
    // deliberately not [serializable] 
    [System.Runtime.InteropServices.ComVisible(true)]
    public class Context 
    { 
        // flags to mark the state of the context object
        // marks the context as the default context 
        internal const int CTX_DEFAULT_CONTEXT   = 0x00000001;

        // marks the context as frozen
        internal const int CTX_FROZEN                = 0x00000002; 

        // Tells the context channel that the context has properties 
        // that use the threadPool themselves. 
        // In that case, the channel does not itself use threadPool.
        // This is OFF by default 
        internal const int CTX_THREADPOOL_AWARE = 0x00000004;

        private const int GROW_BY                        = 0x8;
        private const int STATICS_BUCKET_SIZE           = 0x8; 

        private IContextProperty[] _ctxProps;    // array of name-value pairs of properties 
        private DynamicPropertyHolder _dphCtx;  // Support for Dynamic Sinks 
        private LocalDataStoreHolder _localDataStore;
        private IMessageSink _serverContextChain; 
        private IMessageSink _clientContextChain;
        private AppDomain _appDomain;       // AppDomain property of the context
        private Object[] _ctxStatics;       // Holder for context statics
 
        //**********************
        // This needs to be the first NON-OBJECT field! 
        private IntPtr _internalContext; // address of the VM context object! 
        //**********************
 
        // at this point we just differentiate contexts based on context ID
        private int _ctxID;
        private int _ctxFlags;
        private int _numCtxProps;   // current count of properties 

        // Context statics stuff 
        private int _ctxStaticsCurrentBucket; 
        private int _ctxStaticsFreeIndex;
 
        // Support for dynamic properties.
        private static DynamicPropertyHolder _dphGlobal = new DynamicPropertyHolder();

        // Support for Context Local Storage 
        private static LocalDataStoreMgr _localDataStoreMgr = new LocalDataStoreMgr();
 
        // ContextID counter (for public context id) 
        private static int _ctxIDCounter = 0;
        // < 


        /// 
        [System.Security.SecurityCritical]  // auto-generated_required 
        public Context()
            : this(0) 
        { 
        }
 
        [System.Security.SecurityCritical]  // auto-generated
        private Context(int flags) {

            _ctxFlags = flags; 
            if ((_ctxFlags & CTX_DEFAULT_CONTEXT) != 0)
            { 
                _ctxID = 0;     // ID 0 == default context 
            }
            else 
            {
                _ctxID = Interlocked.Increment(ref _ctxIDCounter);
            }
 
            // Every context inherits the appdomain level properties
            // Get the properties for the appdomain and add it to 
            // this context. 
            DomainSpecificRemotingData data = Thread.GetDomain().RemotingData;
            if(null != data) 
            {
                IContextProperty[] ctxProps = data.AppDomainContextProperties;
                if(null != ctxProps)
                { 
                    for(int i = 0; i < ctxProps.Length; i++)
                    { 
                        SetProperty(ctxProps[i]); 
                    }
                } 
            }

            // Freeze the default context now
            if ((_ctxFlags & CTX_DEFAULT_CONTEXT) != 0) 
            {
                this.Freeze(); 
            } 
            // This call will set up the cycles between the VM & managed context
            // It will also set the managed context's AppDomain property to 
            // the current AppDomain.Will also publish ifthe default ctx, so should be
            // in the very end
            SetupInternalContext((_ctxFlags&CTX_DEFAULT_CONTEXT) == CTX_DEFAULT_CONTEXT);
 
            Message.DebugOut("Creating Context with ID " + _ctxID + " and flags " + flags + " " + Environment.NewLine);
        } 
 
        [System.Security.SecurityCritical]  // auto-generated
        [ResourceExposure(ResourceScope.None)] 
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        private extern void SetupInternalContext(bool bDefault);

    ///  
        [System.Security.SecuritySafeCritical]  // auto-generated
        ~Context() 
        { 
            // We clean up the backing objects only for the non-default
            // contexts. For default contexts these are cleaned up during 
            // AppDomain shutdown.
            if (_internalContext != IntPtr.Zero && (_ctxFlags & CTX_DEFAULT_CONTEXT) == 0)
            {
                CleanupInternalContext(); 
            }
        } 
 
        [System.Security.SecurityCritical]  // auto-generated
        [ResourceExposure(ResourceScope.None)] 
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        private extern void CleanupInternalContext();

        ///  
        public virtual Int32 ContextID
        { 
            [System.Security.SecurityCritical]  // auto-generated_required 
            get
            { 
                return _ctxID;
            }
        }
 
        internal virtual IntPtr InternalContextID
        { 
            get 
            {
                return _internalContext; 
            }
        }

        internal virtual AppDomain AppDomain 
        {
            get {return _appDomain;} 
        } 

        internal bool IsDefaultContext 
        {
            get { return _ctxID == 0; }
        }
 
        /// 
        public static Context DefaultContext 
        { 
            [System.Security.SecurityCritical]  // auto-generated_required
            get 
            {
                return Thread.GetDomain().GetDefaultContext();
            }
        } 

        [System.Security.SecurityCritical]  // auto-generated 
        internal static Context CreateDefaultContext() 
        {
            return new Context(CTX_DEFAULT_CONTEXT); 
        }

        /// 
        [System.Security.SecurityCritical]  // auto-generated_required 
        public virtual IContextProperty GetProperty(String name)
        { 
            if (_ctxProps == null || name == null) 
            {
                return null; 
            }
            IContextProperty prop = null;
            for (int i=0; i<_numCtxProps; i++)
            { 
                if (_ctxProps[i].Name.Equals(name))
                { 
                    prop = _ctxProps[i]; 
                    break;
                } 
            }
            return prop;
        }
 
        /// 
        [System.Security.SecurityCritical]  // auto-generated_required 
        public virtual void SetProperty(IContextProperty prop) 
        {
            // We do not let people add properties to the default context. 
            /* We allow appdomain level properties to be added to the default context
            if ((_ctxFlags & CTX_DEFAULT_CONTEXT) != 0)
            {
                throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_AddContextFrozen")); 
            }
            */ 
 
            if (prop == null || prop.Name == null)
            { 
                throw new ArgumentNullException((prop==null) ? "prop" : "property name");
            }
            Contract.EndContractBlock();
 
            if ((_ctxFlags & CTX_FROZEN) != 0)
            { 
                throw new InvalidOperationException( 
                    Environment.GetResourceString("InvalidOperation_AddContextFrozen"));
            } 

            lock (this)
            {
                // Check if we have a property by this name 
                CheckPropertyNameClash(prop.Name, _ctxProps, _numCtxProps);
 
                // check if we need to grow the array. 
                if (_ctxProps == null || _numCtxProps == _ctxProps.Length)
                { 
                    _ctxProps = GrowPropertiesArray(_ctxProps);
                }
                // now add the property
                _ctxProps[_numCtxProps++] = prop; 
            }
        } 
 
        [System.Security.SecurityCritical]  // auto-generated
        internal virtual void  InternalFreeze() 
        {
            _ctxFlags |= CTX_FROZEN;
            // From this point on attempts to add properties will throw
            // So we don't need to take a lock. 
            for (int i=0; i<_numCtxProps; i++)
            { 
                _ctxProps[i].Freeze(this); 
            }
 
        }
        /// 
        [System.Security.SecurityCritical]  // auto-generated_required
        public virtual void Freeze() 
        {
            lock(this) { 
                if ((_ctxFlags & CTX_FROZEN) != 0) 
                {
                    throw new InvalidOperationException( 
                        Environment.GetResourceString(
                            "InvalidOperation_ContextAlreadyFrozen"));
                }
                InternalFreeze(); 
            }
        } 
 
        internal virtual void SetThreadPoolAware()
        { 
            // Cannot turn off ThreadPool support for the default context
            Contract.Assert(
                (_ctxFlags & CTX_DEFAULT_CONTEXT) == 0,
                "This operation is not allowed on the default context!"); 
            _ctxFlags |= CTX_THREADPOOL_AWARE;
        } 
 
        internal virtual bool IsThreadPoolAware
        { 
            get { return (_ctxFlags & CTX_THREADPOOL_AWARE) == CTX_THREADPOOL_AWARE;}
        }

        ///  
        public virtual IContextProperty[] ContextProperties
        { 
            // we return a copy of the current set of properties 
            // the user may iterate from 0 to array.length on it.
            [System.Security.SecurityCritical]  // auto-generated_required 
            get
            {
                if (_ctxProps == null)
                { 
                    return null;
                } 
                lock (this) 
                {
                    IContextProperty[] retProps = new IContextProperty[_numCtxProps]; 
                    Array.Copy(_ctxProps, retProps, _numCtxProps);
                    return retProps;
                }
            } 
        }
 
        [System.Security.SecurityCritical]  // auto-generated 
        internal static void CheckPropertyNameClash(String name, IContextProperty[] props, int count)
        { 
            for (int i=0; i 0) 
                {
                    // see if this property wants to contribute a ServerContextSink
                    // we have to start chaining in the reverse order
                    prop = _ctxProps[iSink]; 
                    IContributeServerContextSink sink = prop as IContributeServerContextSink;
                    if (null != sink ) 
                    { 
                        // yes, chain the sink ahead of the chain of sinks constructed so far.
                        newServerContextChain = sink.GetServerContextSink( newServerContextChain); 
                        if (newServerContextChain == null)
                        {
                            throw new RemotingException(
                                Environment.GetResourceString( 
                                    "Remoting_Contexts_BadProperty"));
                        } 
                    } 
                }
                lock (this) 
                {
                    if (_serverContextChain == null)
                    {
                        _serverContextChain = newServerContextChain; 
                    }
                } 
            } 
            return _serverContextChain;
        } 

        [System.Security.SecurityCritical]  // auto-generated
        internal virtual IMessageSink GetClientContextChain()
        { 
            Message.DebugOut("Context::GetClientContextChain: IN _ctxID =" + _ctxID + Environment.NewLine);
            if (_clientContextChain == null) 
            { 
                Message.DebugOut("Context::GetClientContextChain: _clientContextChain == null, creating chain" + Environment.NewLine);
                // a bare chain would have just this one sink. 
                IMessageSink newClientContextChain = ClientContextTerminatorSink.MessageSink;

                // now loop over properties to add some real sinks.
                // Note that for the client chain we go through the properties 
                // in the reverse order as compared to the server chain.
                // Thus if a lock was taken as the last action of an incoming 
                // call, it is released as the first action of an outgoing call. 
                Object prop = null;
                int iSink = 0; 
                while (iSink < _numCtxProps)
                {
                    Message.DebugOut("Context::GetClientContextChain: checking property " +
                                     _ctxProps[iSink].Name + Environment.NewLine); 
                    // see if this property wants to contribute a ClientContextSink
                    // we have to start chaining in the reverse order 
                    prop = _ctxProps[iSink]; 
                    IContributeClientContextSink sink = prop as IContributeClientContextSink;
                    if (null != sink) 
                    {
                        Message.DebugOut("Context::GetClientContextChain: calling GetClientContextSink on " +
                                         _ctxProps[iSink].Name + Environment.NewLine);
                        // yes, chain the sink ahead of the chain of sinks constructed so far. 
                        newClientContextChain = sink.GetClientContextSink(newClientContextChain);
                        if (newClientContextChain == null) 
                        { 
                            throw new RemotingException(
                                Environment.GetResourceString( 
                                    "Remoting_Contexts_BadProperty"));
                        }
                    }
                    iSink++; 
                }
                // now check if we ----d and set appropriately 
                lock (this) 
                {
                    if (_clientContextChain==null) 
                    {
                        _clientContextChain = newClientContextChain;
                    }
                    // else the chain we created should get GC-ed. 
                }
            } 
            return _clientContextChain; 
        }
 
        [System.Security.SecurityCritical]  // auto-generated
        internal virtual IMessageSink CreateServerObjectChain(MarshalByRefObject serverObj)
        {
            // a bare chain would just be the dispatcher sink 
            IMessageSink serverObjectChain = new ServerObjectTerminatorSink(serverObj);
 
            // now loop over properties to add some real sinks. 
            Object prop = null;
            int iSink = _numCtxProps; 
            while (iSink-- > 0)
            {
                // see if this property wants to contribute a ServerObjectSink
                // we have to start chaining in the reverse order 
                prop = _ctxProps[iSink];
                IContributeObjectSink sink = prop as IContributeObjectSink; 
                if (null != sink) 
                {
                    // yes, chain the sink ahead of the chain of sinks constructed so far. 
                    serverObjectChain =  sink.GetObjectSink( serverObj, serverObjectChain);
                    if (serverObjectChain == null)
                    {
                            throw new RemotingException( 
                                Environment.GetResourceString(
                                    "Remoting_Contexts_BadProperty")); 
                    } 
                }
            } 
            return serverObjectChain;
        }

        [System.Security.SecurityCritical]  // auto-generated 
        internal virtual IMessageSink CreateEnvoyChain(MarshalByRefObject objectOrProxy)
        { 
            // a bare chain would just be the dispatcher sink 
            IMessageSink envoyChain = EnvoyTerminatorSink.MessageSink;
 
            // now loop over properties to add some real sinks.
            // Note: the sinks in the envoy chain should be in mirror image
            // order relative to sinks on the server side
            Object prop = null; 
            int iSink = 0;
 
            MarshalByRefObject exposedObj = objectOrProxy; 

            while (iSink < _numCtxProps) 
            {
                // see if this property wants to contribute a ClientContextSink
                // we have to start chaining in the reverse order
                prop = _ctxProps[iSink]; 
                IContributeEnvoySink sink = prop as IContributeEnvoySink;
                if (null != sink) 
                { 
                    // yes, chain the sink ahead of the chain of sinks constructed so far.
                    envoyChain = sink.GetEnvoySink(exposedObj, envoyChain); 
                    if (envoyChain == null)
                    {
                        throw new RemotingException(
                            Environment.GetResourceString( 
                                "Remoting_Contexts_BadProperty"));
                    } 
                } 
                iSink++;
            } 
            return envoyChain;
        }

 
        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        //~~~~~~~~~~~~~~~~~~~ Activation Support ~~~~~~~~~~~~~~~~~~~~~~~~ 
        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
        [System.Security.SecurityCritical]  // auto-generated
        internal IMessage NotifyActivatorProperties( 
            IMessage msg, bool bServerSide)
        {
            Contract.Assert( (msg is IConstructionCallMessage)
                                || (msg is IConstructionReturnMessage), 
                            "Bad activation msg type");
            Contract.Assert( !((msg is IConstructionCallMessage) && 
                                (msg is IConstructionReturnMessage)), 
                            "Activation message cannot be both call & return type");
 
            Contract.Assert((_ctxFlags & CTX_FROZEN) == CTX_FROZEN,
                            "ServerContext not frozen during activation!");

 
            // Any exception thrown by the notifications is caught and
            // folded into a return message to return to the caller. 
            IMessage errMsg = null; 

            try 
            {
                // Since the context is frozen the properties array is in
                // effect read-only!
                int iProp = _numCtxProps; 
                Object prop = null;
 
                while (iProp-- != 0) 
                {
                    // see if this property is interested in Activation 
                    prop = _ctxProps[iProp];
                    IContextPropertyActivator activator = prop as IContextPropertyActivator;
                    if (null != activator)
                    { 
                        // yes, notify as appropriate
                        IConstructionCallMessage ccm = msg as IConstructionCallMessage; 
                        if (null != ccm) 
                        {
                            // IConsructionCallMessage on its way forward 
                            if (!bServerSide)
                            {
                                // activation starting at client side
                                activator.CollectFromClientContext(ccm); 
                            }
                            else 
                            { 
                                // activation starting at server side
                                // 
                                activator.DeliverClientContextToServerContext(ccm);
                            }
                        }
                        else 
                        {
                            // IConstructionReturnMessage on its way back 
                            if (bServerSide) 
                            {
                                // activation returning from server side 
                                activator.CollectFromServerContext((IConstructionReturnMessage)msg);
                            }
                            else
                            { 
                                // activation back at client side
                                // < 
                                activator.DeliverServerContextToClientContext((IConstructionReturnMessage)msg); 
                            }
                        } 
                    }
                }
            }
            catch (Exception e) 
            {
                IMethodCallMessage mcm = null; 
                if (msg is IConstructionCallMessage) 
                {
                    mcm = (IMethodCallMessage) msg; 
                }
                else
                {
                    mcm = new ErrorMessage(); 
                }
                errMsg = new ReturnMessage(e, mcm); 
                if (msg != null) 
                {
                    ((ReturnMessage)errMsg).SetLogicalCallContext( 
                            (LogicalCallContext)
                            msg.Properties[Message.CallContextKey]);
                }
            } 
            return errMsg;
        } 
 
    /// 
        public override String ToString() 
        {
            return    "ContextID: " + _ctxID;
        }
 
        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        //~~~~~~~~~~~~~~~~~~~ Transition Support ~~~~~~~~~~~~~~~~~~~~~~~~ 
        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

        // This is the simple cross-context call back function invoke on 
        // the context to do a call-back in.
        /// 
        [System.Security.SecurityCritical]  // auto-generated_required
        public void DoCallBack(CrossContextDelegate deleg) 
        {
            /*DBG Console.WriteLine("public DoCallBack: targetCtx: " 
            + Int32.Format(this.InternalContextID,"x")); DBG*/ 

            if (deleg == null) 
            {
                throw new ArgumentNullException("deleg");
            }
            Contract.EndContractBlock(); 

            if ((_ctxFlags & CTX_FROZEN) == 0) 
            { 
                throw new RemotingException(
                    Environment.GetResourceString( 
                        "Remoting_Contexts_ContextNotFrozenForCallBack"));
            }

            Context currCtx = Thread.CurrentContext; 
            if (currCtx == this)
            { 
                // We are already in the target context, just execute deleg 
                // NOTE: If in the future we decide to leave the context
                // and reenter it for this case we will need to change 
                // Context::RequestCallBack method in VM also!
                deleg();
            }
            else 
            {
                // We pass 0 for target domain ID for x-context case. 
                currCtx.DoCallBackGeneric(this.InternalContextID, deleg); 
                GC.KeepAlive(this);
            } 
        }

        // This is called when EE needs to do a transition and execute some
        // code. Before calling, EE determines if this is a x-domain case. 
        // targetDomainID will be 0 if it is a simple x-context call.
        //< 
        [System.Security.SecurityCritical]  // auto-generated 
        internal static void DoCallBackFromEE(
            IntPtr targetCtxID, IntPtr privateData, int targetDomainID) 
        {
            Contract.Assert(targetCtxID != IntPtr.Zero, "Bad transition context");

            /*DBG Console.WriteLine("private DoCallBackFromEE: targetCtx: " 
            + Int32.Format(targetCtxID,"x")
            + " PvtData: " + Int32.Format(privateData,"x"));DBG*/ 
 
            if (targetDomainID == 0)
            { 
                CallBackHelper cb = new CallBackHelper(
                                            privateData,
                                            true /*fromEE*/,
                                            targetDomainID); 
                CrossContextDelegate ctxDel = new CrossContextDelegate(cb.Func);
                Thread.CurrentContext.DoCallBackGeneric(targetCtxID, ctxDel); 
            } 
            else
            { 
                // for x-appdomain calls, we can't pass a delegate since that
                //   would require us to deserialize it on the other side which
                //   is not allowed for non-public methods.
                TransitionCall msgCall = new TransitionCall(targetCtxID, privateData, targetDomainID); 

                Message.PropagateCallContextFromThreadToMessage(msgCall); 
                //DBG Console.WriteLine("CallBackGeneric starting!"); 
                IMessage retMsg = Thread.CurrentContext.GetClientContextChain().SyncProcessMessage(msgCall);
                Message.PropagateCallContextFromMessageToThread(retMsg); 

                IMethodReturnMessage msg = retMsg as IMethodReturnMessage;
                if (null != msg)
                { 
                    if (msg.Exception != null)
                        throw msg.Exception; 
                } 
            }
        } // DoCallBackFromEE 

                // This is called by both the call back functions above.
        [System.Security.SecurityCritical]  // auto-generated
        internal void DoCallBackGeneric( 
            IntPtr targetCtxID, CrossContextDelegate deleg)
        { 
            TransitionCall msgCall = new TransitionCall(targetCtxID, deleg); 

            Message.PropagateCallContextFromThreadToMessage(msgCall); 
            //DBG Console.WriteLine("CallBackGeneric starting!");
            IMessage retMsg = this.GetClientContextChain().SyncProcessMessage(msgCall);
            if (null != retMsg)
            { 
                Message.PropagateCallContextFromMessageToThread(retMsg);
            } 
 
            IMethodReturnMessage msg = retMsg as IMethodReturnMessage;
            if (null != msg) 
            {
                if (msg.Exception != null)
                    throw msg.Exception;
            } 
            //DBG Console.WriteLine("CallBackGeneric finished!");
        } 
 
        // This is the E-Call that we route the EE-CallBack request to
        [System.Security.SecurityCritical]  // auto-generated 
        [ResourceExposure(ResourceScope.None)]
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        internal static extern void ExecuteCallBackInEE(IntPtr privateData);
 
        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        //~~~~~~~~~~~~~~~~~~~~ Context Local Store  ~~~~~~~~~~~~~~~~~~~~ 
        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

        private LocalDataStore MyLocalStore 
        {
            get
            {
                if (_localDataStore == null) 
                {
                    // It's OK to lock the manager here because it is going to lock 
                    // itself anyway. 
                    lock (_localDataStoreMgr)
                    { 
                        if (_localDataStore == null)
                        {
                            // The local store has not yet been created for this thread.
                            _localDataStore = _localDataStoreMgr.CreateLocalDataStore(); 
                        }
                    } 
                } 
                return _localDataStore.Store;
            } 
        }

        //  All of these are exact shadows of corresponding ThreadLocalStore
        //  APIs. 
        /// 
       [System.Security.SecurityCritical]  // auto-generated_required 
        public static LocalDataStoreSlot AllocateDataSlot() 
        {
            return _localDataStoreMgr.AllocateDataSlot(); 
        }
        /// 
        [System.Security.SecurityCritical]  // auto-generated_required
        public static LocalDataStoreSlot AllocateNamedDataSlot(String name) 
        {
            return _localDataStoreMgr.AllocateNamedDataSlot(name); 
        } 
        /// 
        [System.Security.SecurityCritical]  // auto-generated_required 
        public static LocalDataStoreSlot GetNamedDataSlot(String name)
        {
            return _localDataStoreMgr.GetNamedDataSlot(name);
        } 
        /// 
        [System.Security.SecurityCritical]  // auto-generated_required 
        public static void FreeNamedDataSlot(String name) 
        {
            _localDataStoreMgr.FreeNamedDataSlot(name); 
        }

        /// 
        [System.Security.SecurityCritical]  // auto-generated_required 
        public static void SetData(LocalDataStoreSlot slot, Object data)
        { 
                        Thread.CurrentContext.MyLocalStore.SetData(slot, data); 
        }
 
        /// 
        [System.Security.SecurityCritical]  // auto-generated_required
        public static Object GetData(LocalDataStoreSlot slot)
        { 
            return Thread.CurrentContext.MyLocalStore.GetData(slot);
        } 
 
        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        //~~~~~~~~~~~~~~~~~~~~ Context Statics ~~~~~~~~~~~~~~~~~~~~~~~~~~ 
        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        private int ReserveSlot()
        {
            // This will be called with the context crst held so we 
            // don't take a lock here)
            if (_ctxStatics == null) 
            { 
                // allocate the first bucket
                _ctxStatics = new Object[STATICS_BUCKET_SIZE]; 
                // set next bucket field to null
                _ctxStatics[0] = null;
                _ctxStaticsFreeIndex = 1;
                _ctxStaticsCurrentBucket = 0; 
            }
 
            // See if we have to allocate a new bucket 
            if (_ctxStaticsFreeIndex == STATICS_BUCKET_SIZE)
            { 
                Object[] newBucket = new Object[STATICS_BUCKET_SIZE];

                // walk the chain to locate the last bucket
                Object[] bucket = _ctxStatics; 
                while (bucket[0] != null)
                { 
                    bucket = (Object[]) bucket[0]; 
                }
                // chain in the new bucket 
                bucket[0] = newBucket;
                _ctxStaticsFreeIndex = 1;
                _ctxStaticsCurrentBucket++;
            } 

            // bucket# in highWord, index in lowWord 
            return _ctxStaticsFreeIndex++|_ctxStaticsCurrentBucket<<16; 
        }
        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
        //~~~~~~~~~~~~~~~~~~~~ End Context Statics ~~~~~~~~~~~~~~~~~~~~~~
        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
        //~~~~~~~~~~~~~~~~~~~~ Dynamic Sink Support  ~~~~~~~~~~~~~~~~~~~~
        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
        //   This allows people to register a property implementing IContributeDynamicSink 
        //   with the remoting service. Based on the obj and ctx parameters, the property
        //   is asked to contribute a sink that is placed at some location in the path of 
        //   remoting calls.
        //   The property may be unregistered, which implies that the sink will be dropped
        //   for subsequent remoting calls.
        //   If multiple properties are registered, their sinks may be called in an 
        //   arbitrary order which may change between calls.
        // 
        //   If obj is non null then: 
        //       - if it is a proxy, all calls made on the proxy are intercepted
    //       - if it is a real object, all calls on the object are intercepted 
    //       - the ctx argument must be null
    //   If ctx is non-null then:
    //       - the obj argument must be null
    //       - all calls entering and leaving the context are intercepted 
    //   If both ctx and obj are null then:
    //       - all calls entering and leaving all contexts are intercepted 
    // 
    /// 
        [System.Security.SecuritySafeCritical]  // auto-generated 
        [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.Infrastructure)]
        public static bool RegisterDynamicProperty(IDynamicProperty prop, ContextBoundObject obj, Context ctx)
        {
            bool fRegistered = false; 

            if (prop == null || prop.Name == null || !(prop is IContributeDynamicSink)) 
            { 
                throw new ArgumentNullException("prop");
            } 
            if (obj != null && ctx != null)
            {
                // Exactly one of these is allowed to be non-null.
                throw new ArgumentException(Environment.GetResourceString("Argument_NonNullObjAndCtx")); 
            }
            if (obj != null) 
            { 
                // ctx is ignored and must be null.
                fRegistered = IdentityHolder.AddDynamicProperty(obj, prop); 
            }
            else
            {
                // ctx may or may not be null 
                fRegistered = Context.AddDynamicProperty(ctx, prop);
            } 
 
            return fRegistered;
        } 

    /// 
        [System.Security.SecuritySafeCritical]  // auto-generated
        [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.Infrastructure)] 
        public static bool UnregisterDynamicProperty(String name, ContextBoundObject obj, Context ctx)
        { 
            // name, obj, ctx arguments should be exactly the same as a previous 
            // RegisterDynamicProperty call
            if (name == null) 
            {
                throw new ArgumentNullException("name");
            }
            if (obj != null && ctx != null) 
            {
                throw new ArgumentException(Environment.GetResourceString("Argument_NonNullObjAndCtx")); 
            } 
            Contract.EndContractBlock();
 
            bool fUnregister = false;

            if (obj != null)
            { 
                // ctx is ignored and must be null.
                fUnregister = IdentityHolder.RemoveDynamicProperty(obj, name); 
            } 
            else
            { 
                // ctx may or may not be null
                fUnregister = Context.RemoveDynamicProperty(ctx, name);
            }
 
            return fUnregister;
        } 
 
        /*
         *  Support for dynamic sinks at context level 
         *
         */
        [System.Security.SecurityCritical]  // auto-generated
        internal static bool AddDynamicProperty(Context ctx, IDynamicProperty prop) 
        {
            // Check if we have a property by this name 
            if (ctx != null) 
            {
                return ctx.AddPerContextDynamicProperty(prop); 
            }
            else
            {
                // We have to add a sink that should fire for all contexts 
                return AddGlobalDynamicProperty(prop);
            } 
        } 

        [System.Security.SecurityCritical]  // auto-generated 
        private bool AddPerContextDynamicProperty(IDynamicProperty prop)
        {
            if (_dphCtx == null)
            { 
                DynamicPropertyHolder dph = new DynamicPropertyHolder();
                lock (this) 
                { 
                    if (_dphCtx == null)
                    { 
                        _dphCtx = dph;
                    }
                }
            } 
            return _dphCtx.AddDynamicProperty(prop);
        } 
 
        [System.Security.SecurityCritical]  // auto-generated
        private static bool AddGlobalDynamicProperty(IDynamicProperty prop) 
        {
            return _dphGlobal.AddDynamicProperty(prop);
        }
 
        [System.Security.SecurityCritical]  // auto-generated
        internal static bool RemoveDynamicProperty(Context ctx, String name) 
        { 
            if (ctx != null)
            { 
                return ctx.RemovePerContextDynamicProperty(name);
            }
            else
            { 
                // We have to remove a global property
                return RemoveGlobalDynamicProperty(name); 
            } 
        }
 
        [System.Security.SecurityCritical]  // auto-generated
        private bool RemovePerContextDynamicProperty(String name)
        {
            // We have to remove a property for this context 
            if (_dphCtx == null)
            { 
                throw new RemotingException( 
                    String.Format(
                        CultureInfo.CurrentCulture, Environment.GetResourceString("Remoting_Contexts_NoProperty"), 
                        name
                        ));
            }
            return _dphCtx.RemoveDynamicProperty(name); 
        }
 
        [System.Security.SecurityCritical]  // auto-generated 
        private static bool RemoveGlobalDynamicProperty(String name)
        { 
            return _dphGlobal.RemoveDynamicProperty(name);
        }

        /* 
         *  Returns an array of context specific dynamic properties
         *  registered for this context. The number of such properties 
         *  is designated by length of the returned array. 
         */
        internal virtual IDynamicProperty[] PerContextDynamicProperties 
        {
            get
            {
                if (_dphCtx == null) 
                {
                    return null; 
                } 
                else
                { 
                    return _dphCtx.DynamicProperties;
                }
            }
        } 

        /* 
         *  Returns an array of global dynamic properties 
         *  registered (for all contexts). The number of such properties
         *  is designated by length of the returned array. 
         */
        internal static ArrayWithSize GlobalDynamicSinks
        {
            [System.Security.SecurityCritical]  // auto-generated 
            get
            { 
                return _dphGlobal.DynamicSinks; 
            }
        } 

        internal virtual ArrayWithSize DynamicSinks
        {
            [System.Security.SecurityCritical]  // auto-generated 
            get
            { 
                if (_dphCtx == null) 
                {
                    return null; 
                }
                else
                {
                    return _dphCtx.DynamicSinks; 
                }
            } 
        } 

        [System.Security.SecurityCritical]  // auto-generated 
        internal virtual bool NotifyDynamicSinks(
            IMessage msg,
            bool bCliSide,
            bool bStart, 
            bool bAsync,
            bool bNotifyGlobals) 
        { 
            bool bHasDynamicSinks = false;
 
            if (bNotifyGlobals && (_dphGlobal.DynamicProperties != null))
            {
                ArrayWithSize globalSinks = GlobalDynamicSinks;
                if (globalSinks != null) 
                {
                    DynamicPropertyHolder.NotifyDynamicSinks( 
                                    msg, 
                                    globalSinks,
                                    bCliSide, 
                                    bStart,
                                    bAsync);
                    bHasDynamicSinks = true;
                } 
            }
 
            ArrayWithSize perCtxSinks = DynamicSinks; 
            if (perCtxSinks != null)
            { 
                DynamicPropertyHolder.NotifyDynamicSinks(
                                    msg,
                                    perCtxSinks,
                                    bCliSide, 
                                    bStart,
                                    bAsync); 
                bHasDynamicSinks = true; 
            }
 
            return bHasDynamicSinks;
        } // NotifyDynamicSinks

        //******************** END: Dynamic Sink Support ******************** 
    }
 
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
    //~~~~~~~~~~~~~~~~~~~ More Transition Support ~~~~~~~~~~~~~~~~~~~
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
    // This class is used as the backing object that implements a delegate
    // function to be used for internal call-backs. The delegate type must
    // be CrossContextDelegate (void Func(void) below) since we are using
    // the DoCallBackGeneric also as the underlying mechanism for the 
    // exposed cross-context callbacks.
    [Serializable] 
    internal class CallBackHelper 
    {
        // Some flag definitions 
        internal const int RequestedFromEE = 0x00000001;   // callBack from EE
        internal const int XDomainTransition= 0x00000100;  // going x-domain

        internal bool IsEERequested 
        {
            get {return (_flags&RequestedFromEE)==RequestedFromEE;} 
            set {if (value) {_flags |= RequestedFromEE;}} 
        }
 
        internal bool IsCrossDomain
        {
            set {if (value) {_flags |= XDomainTransition;}}
        } 

        int _flags; 
        IntPtr _privateData; 

        internal CallBackHelper(IntPtr privateData, bool bFromEE, int targetDomainID) 
        {
            this.IsEERequested = bFromEE;
            this.IsCrossDomain = (targetDomainID!=0);
            _privateData = privateData; 
        }
 
        [System.Security.SecurityCritical]  // auto-generated 
        internal void Func()
        { 
            /*DBG Console.WriteLine("DelegHelper::Func CTX:"
            + Int32.Format(Thread.CurrentContext.InternalContextID,"x")
            +Environment.NewLine + "DMN: " + Int32.Format(Thread.GetDomainID(),"x")); DBG*/
            if (IsEERequested) 
            {
                //DBG Console.WriteLine("Executing EE callback "); 
 
                // EE requested this call back, call EE with its private data
                Context.ExecuteCallBackInEE(_privateData); 

                //DBG Console.WriteLine("Execute CallBackInEE returned: " + Int32.Format(_retVal,"x"));
            }
            else 
            {
                //DBG Console.WriteLine("Executing non-EE internal callback"); 
            } 
        }
    }       // class CallBackHelper 
}       //nameSpace Remoting

// 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