The Labs \ Source Viewer \ SSCLI \ System.Runtime.Remoting.Proxies \ RealProxy

  1. // ==++==
  2. //
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. //
  14. // ==--==
  15. /*============================================================
  16. **
  17. ** File:    RealProxy.cs
  18. **
  19. **
  20. ** Purpose: Defines the base class from which proxy should
  21. **          derive
  22. **
  23. **
  24. ===========================================================*/
  25. namespace System.Runtime.Remoting.Proxies
  26. {
  27.     using System;
  28.     using System.Reflection;
  29.     using System.Runtime.CompilerServices;
  30.     using System.Runtime.InteropServices;
  31.     using System.Runtime.Remoting;
  32.     using System.Runtime.Remoting.Messaging;
  33.     using System.Runtime.Remoting.Metadata;
  34.     using System.Runtime.Remoting.Channels;
  35.     using System.Runtime.Remoting.Activation;
  36.     using System.Runtime.Remoting.Services;
  37.     using System.Runtime.Serialization;
  38.     using System.Security;
  39.     using System.Security.Permissions;
  40.     using System.Security.Principal;
  41.     using System.Threading;
  42.     using System.Runtime.ConstrainedExecution;
  43.     using System.Globalization;
  44.    
  45.    
  46.    
  47.     // NOTE: Keep this in sync with unmanaged enum definition in Remoting.h
  48.     [Serializable()]
  49.     internal enum CallType
  50.     {
  51.         InvalidCall = 0,
  52.         MethodCall = 1,
  53.         ConstructorCall = 2
  54.     }
  55.    
  56.     [Flags()]
  57.     internal enum RealProxyFlags
  58.     {
  59.         None = 0,
  60.         RemotingProxy = 1,
  61.         Initialized = 2
  62.     }
  63.    
  64.     // NOTE: Keep this in sync with unmanaged struct "messageData" in Remoting.h
  65.     [System.Runtime.InteropServices.StructLayout(LayoutKind.Sequential)]
  66.     internal struct MessageData
  67.     {
  68.         internal IntPtr pFrame;
  69.         internal IntPtr pMethodDesc;
  70.         internal IntPtr pDelegateMD;
  71.         internal IntPtr pSig;
  72.         internal IntPtr thGoverningType;
  73.         internal int iFlags;
  74.     }
  75.    
  76.    
  77.    
  78.     [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure)]
  79.     [SecurityPermissionAttribute(SecurityAction.InheritanceDemand, Flags = SecurityPermissionFlag.Infrastructure)]
  80.     [System.Runtime.InteropServices.ComVisible(true)]
  81.     public abstract class RealProxy
  82.     {
  83.         // ************* NOTE ******
  84.         // Object.h has unmanaged structure which maps this layout
  85.         // if you add/remove/change fields make sure to update the structure
  86.         // in object.h also
  87.        
  88.         // Private members
  89.         private object _tp;
  90.        
  91.         private object _identity;
  92.        
  93.         private MarshalByRefObject _serverObject;
  94.        
  95.         private RealProxyFlags _flags;
  96.        
  97.         internal GCHandle _srvIdentity;
  98.        
  99.         internal int _optFlags;
  100.        
  101.         internal int _domainID;
  102.        
  103.         // Static members
  104.         private static IntPtr _defaultStub = GetDefaultStub();
  105.        
  106.         private static IntPtr _defaultStubValue = new IntPtr(-1);
  107.        
  108.         private static object _defaultStubData = _defaultStubValue;
  109.        
  110.        
  111.         // Constructor
  112.         protected RealProxy(Type classToProxy) : this(classToProxy, (IntPtr)0, null)
  113.         {
  114.         }
  115.        
  116.         [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
  117.         protected RealProxy(Type classToProxy, IntPtr stub, object stubData)
  118.         {
  119.             if (!classToProxy.IsMarshalByRef && !classToProxy.IsInterface) {
  120.                 throw new ArgumentException(Environment.GetResourceString("Remoting_Proxy_ProxyTypeIsNotMBR"));
  121.             }
  122.            
  123.             if ((IntPtr)0 == stub) {
  124.                 BCLDebug.Assert((IntPtr)0 != _defaultStub, "Default stub not set up");
  125.                
  126.                 // The default stub checks for match of contexts defined by us
  127.                 stub = _defaultStub;
  128.                 // Start with a value of -1 because 0 is reserved for the default context
  129.                 stubData = _defaultStubData;
  130.             }
  131.            
  132.             _tp = null;
  133.             if (stubData == null) {
  134.                 throw new ArgumentNullException("stubdata");
  135.             }
  136.             _tp = RemotingServices.CreateTransparentProxy(this, classToProxy, stub, stubData);
  137.             RemotingProxy rp = this as RemotingProxy;
  138.             if (rp != null) {
  139.                 _flags |= RealProxyFlags.RemotingProxy;
  140.             }
  141.         }
  142.        
  143.         // This is used (along the frequent path) of Invoke to avoid
  144.         // casting to RemotingProxy
  145.         internal bool IsRemotingProxy()
  146.         {
  147.             return (_flags & RealProxyFlags.RemotingProxy) == RealProxyFlags.RemotingProxy;
  148.         }
  149.        
  150.         // This is mainly used for RemotingProxy case. It may be worthwhile
  151.         // to make this virtual so extensible proxies can make use of this
  152.         // (and other flags) as well.
  153.         internal bool Initialized {
  154.            
  155.             get { return (_flags & RealProxyFlags.Initialized) == RealProxyFlags.Initialized; }
  156.             set {
  157.                 if (value) {
  158.                     _flags |= RealProxyFlags.Initialized;
  159.                 }
  160.                 else {
  161.                     _flags &= ~RealProxyFlags.Initialized;
  162.                 }
  163.             }
  164.         }
  165.        
  166.         // Method to initialize the server object for x-context scenarios
  167.         // in an extensible way
  168.         [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
  169.         [System.Runtime.InteropServices.ComVisible(true)]
  170.         public IConstructionReturnMessage InitializeServerObject(IConstructionCallMessage ctorMsg)
  171.         {
  172.             IConstructionReturnMessage retMsg = null;
  173.            
  174.             if (_serverObject == null) {
  175.                 Type svrType = GetProxiedType();
  176.                 if ((ctorMsg != null) && (ctorMsg.ActivationType != svrType)) {
  177.                     throw new RemotingException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Remoting_Proxy_BadTypeForActivation"), svrType.FullName, ctorMsg.ActivationType));
  178.                 }
  179.                
  180.                 // Create a blank object
  181.                 _serverObject = RemotingServices.AllocateUninitializedObject(svrType);
  182.                
  183.                 // If the stub is the default stub, then set the server context
  184.                 // to be the current context.
  185.                 SetContextForDefaultStub();
  186.                
  187.                 // OK... we are all set to run the constructor call on the uninitialized object
  188.                 MarshalByRefObject proxy = (MarshalByRefObject)GetTransparentProxy();
  189.                 IMethodReturnMessage msg = null;
  190.                 Exception e = null;
  191.                 if (null != ctorMsg) {
  192.                     msg = RemotingServices.ExecuteMessage(proxy, ctorMsg);
  193.                     e = msg.Exception;
  194.                 }
  195.                 else {
  196.                     try {
  197.                         RemotingServices.CallDefaultCtor(proxy);
  198.                     }
  199.                     catch (Exception excep) {
  200.                         e = excep;
  201.                     }
  202.                 }
  203.                
  204.                 // Construct a return message
  205.                 if (null == e) {
  206.                     object[] outArgs = (msg == null ? null : msg.OutArgs);
  207.                     int outLength = (null == outArgs ? 0 : outArgs.Length);
  208.                     LogicalCallContext callCtx = (msg == null ? null : msg.LogicalCallContext);
  209.                     retMsg = new ConstructorReturnMessage(proxy, outArgs, outLength, callCtx, ctorMsg);
  210.                    
  211.                     // setup identity
  212.                     SetupIdentity();
  213.                     if (IsRemotingProxy()) {
  214.                         ((RemotingProxy)this).Initialized = true;
  215.                     }
  216.                 }
  217.                 else {
  218.                     // Exception occurred
  219.                     retMsg = new ConstructorReturnMessage(e, ctorMsg);
  220.                 }
  221.             }
  222.            
  223.            
  224.             return retMsg;
  225.         }
  226.        
  227.         [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
  228.         protected MarshalByRefObject GetUnwrappedServer()
  229.         {
  230.             return UnwrappedServerObject;
  231.         }
  232.        
  233.         [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
  234.         protected MarshalByRefObject DetachServer()
  235.         {
  236.             object tp = GetTransparentProxy();
  237.             if (tp != null)
  238.                 RemotingServices.ResetInterfaceCache(tp);
  239.             MarshalByRefObject server = _serverObject;
  240.             _serverObject = null;
  241.             server.__ResetServerIdentity();
  242.             return server;
  243.         }
  244.        
  245.         [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
  246.         protected void AttachServer(MarshalByRefObject s)
  247.         {
  248.             object tp = GetTransparentProxy();
  249.             if (tp != null)
  250.                 RemotingServices.ResetInterfaceCache(tp);
  251.             AttachServerHelper(s);
  252.         }
  253.        
  254.         private void SetupIdentity()
  255.         {
  256.             if (_identity == null) {
  257.                 _identity = IdentityHolder.FindOrCreateServerIdentity((MarshalByRefObject)_serverObject, null, IdOps.None);
  258.                 // Set the reference to the proxy in the identity object
  259.                 ((Identity)_identity).RaceSetTransparentProxy(GetTransparentProxy());
  260.             }
  261.         }
  262.        
  263.         private void SetContextForDefaultStub()
  264.         {
  265.             // Check whether the stub is ours or not...
  266.             if (GetStub() == _defaultStub) {
  267.                 // Yes.. setup the context in the TP so that
  268.                 // contexts can be matched correctly...
  269.                 object oVal = GetStubData(this);
  270.                 if (oVal is IntPtr) {
  271.                     IntPtr iVal = (IntPtr)oVal;
  272.                    
  273.                     // Set the stub data only if it has been set to our default value,
  274.                     // otherwise, the user has already indicated a preference for the
  275.                     // stub data.
  276.                     if (iVal.Equals(_defaultStubValue)) {
  277.                         SetStubData(this, Thread.CurrentContext.InternalContextID);
  278.                     }
  279.                 }
  280.             }
  281.         }
  282.        
  283.        
  284.         // Check whether the current context is the same as the
  285.         // server context
  286.         internal bool DoContextsMatch()
  287.         {
  288.             bool fMatch = false;
  289.            
  290.             // Check whether the stub is ours or not...
  291.             if (GetStub() == _defaultStub) {
  292.                 // Yes.. setup the context in the TP so that
  293.                 // contexts can be matched correctly...
  294.                 object oVal = GetStubData(this);
  295.                 if (oVal is IntPtr) {
  296.                     IntPtr iVal = (IntPtr)oVal;
  297.                     // Match the internal context ids...
  298.                     if (iVal.Equals(Thread.CurrentContext.InternalContextID)) {
  299.                         fMatch = true;
  300.                     }
  301.                 }
  302.             }
  303.            
  304.             return fMatch;
  305.         }
  306.        
  307.         // This is directly called by RemotingServices::Wrap() when it needs
  308.         // to bind a proxy with an uninitialized contextBound server object
  309.         internal void AttachServerHelper(MarshalByRefObject s)
  310.         {
  311.             if (s == null || _serverObject != null) {
  312.                 throw new ArgumentException(Environment.GetResourceString("ArgumentNull_Generic"), "s");
  313.             }
  314.             _serverObject = s;
  315.             // setup identity
  316.             SetupIdentity();
  317.         }
  318.        
  319.         // Gets the stub pointer stashed away in the transparent proxy.
  320.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  321.         private extern IntPtr GetStub();
  322.        
  323.         // Sets the stub data
  324.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  325.         [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
  326.         public static extern void SetStubData(RealProxy rp, object stubData);
  327.        
  328.         internal void SetSrvInfo(GCHandle srvIdentity, int domainID)
  329.         {
  330.             _srvIdentity = srvIdentity;
  331.             _domainID = domainID;
  332.         }
  333.        
  334.         // Gets the stub data
  335.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  336.         public static extern object GetStubData(RealProxy rp);
  337.        
  338.         // Gets the default stub implemented by us
  339.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  340.         private static extern IntPtr GetDefaultStub();
  341.        
  342.        
  343.         // Accessor to obtain the type being proxied
  344.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  345.         public extern Type GetProxiedType();
  346.        
  347.         // Method to which transparent proxy delegates when
  348.         // it gets called
  349.         public abstract IMessage Invoke(IMessage msg);
  350.        
  351.         public virtual ObjRef CreateObjRef(Type requestedType)
  352.         {
  353.             if (_identity == null) {
  354.                 throw new RemotingException(Environment.GetResourceString("Remoting_NoIdentityEntry"));
  355.             }
  356.            
  357.             return new ObjRef((MarshalByRefObject)GetTransparentProxy(), requestedType);
  358.         }
  359.        
  360.         public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
  361.         {
  362.             object obj = GetTransparentProxy();
  363.             RemotingServices.GetObjectData(obj, info, context);
  364.         }
  365.        
  366.         private static void HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
  367.         {
  368.             IMethodReturnMessage mrm = retMsg as IMethodReturnMessage;
  369.             if (retMsg == null || (mrm == null)) {
  370.                 throw new RemotingException(Environment.GetResourceString("Remoting_Message_BadType"));
  371.             }
  372.            
  373.             Exception e = mrm.Exception;
  374.            
  375.             if (e != null) {
  376.                 throw e.PrepForRemoting();
  377.             }
  378.             else {
  379.                 if (!(retMsg is StackBasedReturnMessage)) {
  380.                     if (reqMsg is Message) {
  381.                         PropagateOutParameters(reqMsg, mrm.Args, mrm.ReturnValue);
  382.                     }
  383.                     else if (reqMsg is ConstructorCallMessage) {
  384.                         // NOTE: We do not extract the return value as
  385.                         // the process of returning a value from a ConstructorCallMessage
  386.                         // results in marshaling.
  387.                         PropagateOutParameters(reqMsg, mrm.Args, null);
  388.                     }
  389.                 }
  390.             }
  391.         }
  392.        
  393.         // Propagate the out parameters to the stack. This should be called once
  394.         // the call has finished. The input message parameter should be the same
  395.         // as the one which was passed to the first sink to start the call.
  396.         static internal void PropagateOutParameters(IMessage msg, object[] outArgs, object returnValue)
  397.         {
  398.             // Check for method call
  399.             Message m = msg as Message;
  400.            
  401.             // Check for constructor call
  402.             if (null == m) {
  403.                 ConstructorCallMessage ccm = msg as ConstructorCallMessage;
  404.                 if (null != ccm) {
  405.                     m = ccm.GetMessage();
  406.                 }
  407.             }
  408.            
  409.             if (null == m) {
  410.                 throw new ArgumentException(Environment.GetResourceString("Remoting_Proxy_ExpectedOriginalMessage"));
  411.             }
  412.            
  413.             MethodBase mb = m.GetMethodBase();
  414.             RemotingMethodCachedData cache = InternalRemotingServices.GetReflectionCachedData(mb);
  415.             if (outArgs != null && outArgs.Length > 0) {
  416.                 object[] args = m.Args;
  417.                 // original arguments
  418.                 // If a byref parameter is marked only with [In], we need to copy the
  419.                 // original value from the request message into outargs, so that the
  420.                 // value won't be bashed by CMessage::PropagateOutParameters below.
  421.                 ParameterInfo[] parameters = cache.Parameters;
  422.                 foreach (int index in cache.MarshalRequestArgMap) {
  423.                     ParameterInfo param = parameters[index];
  424.                     if (param.IsIn && param.ParameterType.IsByRef) {
  425.                         if (!param.IsOut)
  426.                             outArgs[index] = args[index];
  427.                     }
  428.                 }
  429.                
  430.                 // copy non-byref arrays back into the same instance
  431.                 if (cache.NonRefOutArgMap.Length > 0) {
  432.                     foreach (int index in cache.NonRefOutArgMap) {
  433.                         Array arg = args[index] as Array;
  434.                         if (arg != null) {
  435.                             Array.Copy((Array)outArgs[index], arg, arg.Length);
  436.                         }
  437.                     }
  438.                 }
  439.                
  440.                 // validate by-ref args (This must be done last)
  441.                 int[] outRefArgMap = cache.OutRefArgMap;
  442.                 if (outRefArgMap.Length > 0) {
  443.                     foreach (int index in outRefArgMap) {
  444.                         ValidateReturnArg(outArgs[index], parameters[index].ParameterType);
  445.                     }
  446.                 }
  447.             }
  448.            
  449.             // validate return value
  450.             // (We don't validate Message.BeginAsync because the return value
  451.             // is always an IAsyncResult and the method base is the one that
  452.             // represents the underlying synchronous method).
  453.             int callType = m.GetCallType();
  454.             if ((callType & Message.CallMask) != Message.BeginAsync) {
  455.                 Type returnType = cache.ReturnType;
  456.                 if (returnType != null) {
  457.                     ValidateReturnArg(returnValue, returnType);
  458.                 }
  459.             }
  460.            
  461.             m.PropagateOutParameters(outArgs, returnValue);
  462.         }
  463.         // PropagateOutParameters
  464.         private static void ValidateReturnArg(object arg, Type paramType)
  465.         {
  466.             if (paramType.IsByRef)
  467.                 paramType = paramType.GetElementType();
  468.            
  469.             if (paramType.IsValueType) {
  470.                 if (arg == null) {
  471.                     if (!(paramType.IsGenericType && paramType.GetGenericTypeDefinition() == typeof(Nullable<>)))
  472.                         throw new RemotingException(Environment.GetResourceString("Remoting_Proxy_ReturnValueTypeCannotBeNull"));
  473.                 }
  474.                 else if (!paramType.IsInstanceOfType(arg)) {
  475.                     throw new InvalidCastException(Environment.GetResourceString("Remoting_Proxy_BadReturnType"));
  476.                 }
  477.             }
  478.             else {
  479.                 if (arg != null) {
  480.                     if (!paramType.IsInstanceOfType(arg)) {
  481.                         throw new InvalidCastException(Environment.GetResourceString("Remoting_Proxy_BadReturnType"));
  482.                     }
  483.                 }
  484.             }
  485.         }
  486.         // ValidateReturnArg
  487.         // This is shared code path that executes when an EndInvoke is called
  488.         // either on a delegate on a proxy
  489.         // OR a regular delegate (called asynchronously).
  490.         static internal IMessage EndInvokeHelper(Message reqMsg, bool bProxyCase)
  491.         {
  492.             AsyncResult ar = reqMsg.GetAsyncResult() as AsyncResult;
  493.             IMessage retMsg = null;
  494.             // used for proxy case only!
  495.             if (ar == null) {
  496.                 throw new RemotingException(Environment.GetResourceString("Remoting_Message_BadAsyncResult"));
  497.             }
  498.             if (ar.AsyncDelegate != reqMsg.GetThisPtr()) {
  499.                 throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_MismatchedAsyncResult"));
  500.             }
  501.             if (!ar.IsCompleted) {
  502.                 // Note: using ThreadPoolAware to detect if this is a
  503.                 // ThreadAffinity or Synchronization context.
  504.                 ar.AsyncWaitHandle.WaitOne(Int32.MaxValue, Thread.CurrentContext.IsThreadPoolAware);
  505.             }
  506.            
  507.             lock (ar) {
  508.                 if (ar.EndInvokeCalled)
  509.                     throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_EndInvokeCalledMultiple"));
  510.                
  511.                 ar.EndInvokeCalled = true;
  512.                
  513.                
  514.                 IMethodReturnMessage mrm = (IMethodReturnMessage)ar.GetReplyMessage();
  515.                
  516.                 BCLDebug.Assert(mrm != null, "Reply sink should ensure we have a reply message before signalling");
  517.                
  518.                 // For the proxy case this is handled by RealProxy
  519.                 if (!bProxyCase) {
  520.                     Exception e = mrm.Exception;
  521.                    
  522.                     if (e != null) {
  523.                         // throw e;
  524.                         throw e.PrepForRemoting();
  525.                     }
  526.                     else {
  527.                         reqMsg.PropagateOutParameters(mrm.Args, mrm.ReturnValue);
  528.                     }
  529.                 }
  530.                 else {
  531.                     retMsg = mrm;
  532.                 }
  533.                 // Merge the call context back into the thread that
  534.                 // called EndInvoke
  535.                 CallContext.GetLogicalCallContext().Merge(mrm.LogicalCallContext);
  536.             }
  537.             // Will be non-null only for proxy case!
  538.             return retMsg;
  539.         }
  540.         // EndInvokeHelper
  541.        
  542.         // Method used for traversing back to the TP
  543.         public virtual object GetTransparentProxy()
  544.         {
  545.             return _tp;
  546.         }
  547.        
  548.         internal MarshalByRefObject UnwrappedServerObject {
  549.             get { return (MarshalByRefObject)_serverObject; }
  550.         }
  551.        
  552.         internal virtual Identity IdentityObject {
  553.             [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
  554.             get { return (Identity)_identity; }
  555.            
  556.             set { _identity = value; }
  557.         }
  558.        
  559.         // Private method invoked by the transparent proxy
  560.         private void PrivateInvoke(ref MessageData msgData, int type)
  561.         {
  562.             IMessage reqMsg = null;
  563.             CallType callType = (CallType)type;
  564.             IMessage retMsg = null;
  565.             int msgFlags = -1;
  566.            
  567.             // Used only for Construction case
  568.             RemotingProxy rp = null;
  569.            
  570.             // Create a message object based on the type of call
  571.             if (CallType.MethodCall == callType) {
  572.                 Message msg = new Message();
  573.                 msg.InitFields(msgData);
  574.                 reqMsg = msg;
  575.                 msgFlags = msg.GetCallType();
  576.             }
  577.             else if (CallType.ConstructorCall == (CallType)callType) {
  578.                 // We use msgFlags to handle CallContext around
  579.                 // the virtual call to Invoke()
  580.                 msgFlags = Message.Sync;
  581.                
  582.                 rp = this as RemotingProxy;
  583.                 ConstructorCallMessage ctorMsg = null;
  584.                 bool bIsWellKnown = false;
  585.                 if (!IsRemotingProxy()) {
  586.                     // Create a new constructor call message
  587.                     ctorMsg = new ConstructorCallMessage(null, null, null, GetProxiedType());
  588.                 }
  589.                 else {
  590.                     // Extract the constructor message set in the first step of activation.
  591.                     ctorMsg = rp.ConstructorMessage;
  592.                     // If the proxy is a wellknown client proxy, we don't
  593.                     // need to run the c'tor.
  594.                     Identity id = rp.IdentityObject;
  595.                     if (id != null)
  596.                         bIsWellKnown = id.IsWellKnown();
  597.                 }
  598.                
  599.                 if ((null == ctorMsg) || bIsWellKnown) {
  600.                     // This is also used to short-circuit the activation path
  601.                     // when we have a well known proxy that has already been
  602.                     // initialized (there's a race condition if we don't do this).
  603.                     //
  604.                    
  605.                     // This is a special case, where we have a remoting proxy
  606.                     // but the constructormessage hasn't been setup.
  607.                     // so let us just bail out..
  608.                     // this is currently used by ServicedComponent's for cross appdomain
  609.                     // pooling:
  610.                     //
  611.                     ctorMsg = new ConstructorCallMessage(null, null, null, GetProxiedType());
  612.                     // Set the constructor frame info in the CCM
  613.                     ctorMsg.SetFrame(msgData);
  614.                     reqMsg = ctorMsg;
  615.                    
  616.                     // If this was the default ctor, check that default .ctor was called.
  617.                     if (bIsWellKnown) {
  618.                         BCLDebug.Assert(rp != null, "RemotingProxy expected here!");
  619.                         // Clear any cached ctorMsg on the RemotingProxy
  620.                         rp.ConstructorMessage = null;
  621.                        
  622.                         // We did execute a Connect. Throw if the client
  623.                         // code is also trying to use a non-default constructor at
  624.                         // the same time.
  625.                         if (ctorMsg.ArgCount != 0) {
  626.                             throw new RemotingException(Environment.GetResourceString("Remoting_Activation_WellKnownCTOR"));
  627.                         }
  628.                     }
  629.                    
  630.                     // Create a constructor return message
  631.                     retMsg = new ConstructorReturnMessage((MarshalByRefObject)GetTransparentProxy(), null, 0, null, ctorMsg);
  632.                 }
  633.                 else {
  634.                     // Set the constructor frame info in the CCM
  635.                     ctorMsg.SetFrame(msgData);
  636.                     reqMsg = ctorMsg;
  637.                 }
  638.             }
  639.             else {
  640.                 BCLDebug.Assert(false, "Unknown call type");
  641.             }
  642.            
  643.             // Make sure that outgoing remote calls are counted.
  644.             ChannelServices.IncrementRemoteCalls();
  645.            
  646.             // For non-remoting proxies, EndAsync should not call Invoke()
  647.             // because the proxy cannot support Async and the call has already
  648.             // finished executing in BeginAsync
  649.             if (!IsRemotingProxy() && ((msgFlags & Message.EndAsync) == Message.EndAsync)) {
  650.                
  651.                 Message msg = reqMsg as Message;
  652.                 retMsg = EndInvokeHelper(msg, true);
  653.                 BCLDebug.Assert(null != retMsg, "null != retMsg");
  654.             }
  655.            
  656.             // Invoke
  657.             BCLDebug.Assert(null != reqMsg, "null != reqMsg");
  658.             if (null == retMsg) {
  659.                 // NOTE: there are cases where we setup a return message
  660.                 // and we don't want the activation call to go through
  661.                 // refer to the note above for ServicedComponents and Cross Appdomain
  662.                 // pooling
  663.                
  664.                 LogicalCallContext cctx = null;
  665.                 Thread currentThread = Thread.CurrentThread;
  666.                 // Pick up or clone the call context from the thread
  667.                 // and install it in the reqMsg as appropriate
  668.                 cctx = currentThread.GetLogicalCallContext();
  669.                 SetCallContextInMessage(reqMsg, msgFlags, cctx);
  670.                
  671.                 // Add the outgoing "Header"'s to the message.
  672.                 cctx.PropagateOutgoingHeadersToMessage(reqMsg);
  673.                 retMsg = Invoke(reqMsg);
  674.                
  675.                 // Get the call context returned and set it on the thread
  676.                 ReturnCallContextToThread(currentThread, retMsg, msgFlags, cctx);
  677.                
  678.                 // Pull response "Header"'s out of the message
  679.                 CallContext.GetLogicalCallContext().PropagateIncomingHeadersToCallContext(retMsg);
  680.             }
  681.            
  682.             if (!IsRemotingProxy() && ((msgFlags & Message.BeginAsync) == Message.BeginAsync)) {
  683.                
  684.                 // This was a begin-async on a non-Remoting Proxy. For V-1 they
  685.                 // cannot support Async and end up doing a Sync call. We need
  686.                 // to fill up here to make the call look like async to
  687.                 // the caller.
  688.                 // Create the async result to return
  689.                 Message msg = reqMsg as Message;
  690.                 AsyncResult ar = new AsyncResult(msg);
  691.                 // Tell the async result that the call has actually completed
  692.                 // so it can hold on to the return message.
  693.                 ar.SyncProcessMessage(retMsg);
  694.                 // create a returnMessage to propagate just the asyncResult back
  695.                 // to the caller's stack.
  696.                     /*cctx*/                retMsg = new ReturnMessage(ar, null, 0, null, msg);
  697.             }
  698.            
  699.             // Propagate out parameters
  700.             HandleReturnMessage(reqMsg, retMsg);
  701.            
  702.             // For constructor calls do some extra bookkeeping
  703.             if (CallType.ConstructorCall == callType) {
  704.                 // NOTE: It is the responsiblity of the callee to propagate
  705.                 // the out parameters
  706.                
  707.                 // Everything went well, we are ready to return
  708.                 // a proxy to the caller
  709.                 // Extract the return value
  710.                 MarshalByRefObject retObj = null;
  711.                 IConstructionReturnMessage ctorRetMsg = retMsg as IConstructionReturnMessage;
  712.                 if (null == ctorRetMsg) {
  713.                     throw new RemotingException(Environment.GetResourceString("Remoting_Proxy_BadReturnTypeForActivation"));
  714.                 }
  715.                
  716.                 ConstructorReturnMessage crm = ctorRetMsg as ConstructorReturnMessage;
  717.                 if (null != crm) {
  718.                     // If return message is of type ConstructorReturnMessage
  719.                     // this is an in-appDomain activation. So no unmarshaling
  720.                     // needed.
  721.                    
  722.                     retObj = (MarshalByRefObject)crm.GetObject();
  723.                     if (retObj == null) {
  724.                         throw new RemotingException(Environment.GetResourceString("Remoting_Activation_NullReturnValue"));
  725.                     }
  726.                 }
  727.                 else {
  728.                     // Fetch the objRef out of the returned message and unmarshal it
  729.                         /*fRefine*/                    retObj = (MarshalByRefObject)RemotingServices.InternalUnmarshal((ObjRef)ctorRetMsg.ReturnValue, GetTransparentProxy(), true);
  730.                    
  731.                     if (retObj == null) {
  732.                         throw new RemotingException(Environment.GetResourceString("Remoting_Activation_NullFromInternalUnmarshal"));
  733.                     }
  734.                 }
  735.                
  736.                 if (retObj != (MarshalByRefObject)GetTransparentProxy()) {
  737.                     throw new RemotingException(Environment.GetResourceString("Remoting_Activation_InconsistentState"));
  738.                 }
  739.                
  740.                 if (IsRemotingProxy()) {
  741.                     // Clear any cached ctorMsg on the RemotingProxy
  742.                     rp.ConstructorMessage = null;
  743.                 }
  744.             }
  745.         }
  746.        
  747.         void SetCallContextInMessage(IMessage reqMsg, int msgFlags, LogicalCallContext cctx)
  748.         {
  749.             BCLDebug.Assert(msgFlags != -1, "Unexpected msgFlags?");
  750.             Message msg = reqMsg as Message;
  751.            
  752.             switch (msgFlags) {
  753.                 case Message.Sync:
  754.                     if (msg != null) {
  755.                         msg.SetLogicalCallContext(cctx);
  756.                     }
  757.                     else {
  758.                         ((ConstructorCallMessage)reqMsg).SetLogicalCallContext(cctx);
  759.                     }
  760.                     break;
  761.             }
  762.         }
  763.        
  764.         void ReturnCallContextToThread(Thread currentThread, IMessage retMsg, int msgFlags, LogicalCallContext currCtx)
  765.         {
  766.             if (msgFlags == Message.Sync) {
  767.                 if (retMsg == null)
  768.                     return;
  769.                
  770.                 IMethodReturnMessage mrm = retMsg as IMethodReturnMessage;
  771.                 if (mrm == null)
  772.                     return;
  773.                
  774.                 LogicalCallContext retCtx = mrm.LogicalCallContext;
  775.                 if (retCtx == null) {
  776.                     currentThread.SetLogicalCallContext(currCtx);
  777.                     return;
  778.                 }
  779.                
  780.                 if (!(mrm is StackBasedReturnMessage)) {
  781.                     LogicalCallContext oldCtx = currentThread.SetLogicalCallContext(retCtx);
  782.                     if ((object)oldCtx != (object)retCtx) {
  783.                         // If the new call context does not match the old call context,
  784.                         // we must have gone remote. We need to keep the preserve
  785.                         // the principal from the original call context.
  786.                         IPrincipal principal = oldCtx.Principal;
  787.                         if (principal != null)
  788.                             retCtx.Principal = principal;
  789.                     }
  790.                 }
  791.                 //for other types (async/one-way etc) there is nothing to be
  792.                 //done as we have just finished processing BeginInvoke or EndInvoke
  793.             }
  794.         }
  795.        
  796.         internal virtual void Wrap()
  797.         {
  798.             // EXTENSIBILITY:
  799.             // If this is a serverID, set the native context field in the TP
  800.             ServerIdentity serverID = _identity as ServerIdentity;
  801.             if ((null != serverID) && (this is RemotingProxy)) {
  802.                 BCLDebug.Assert(null != serverID.ServerContext, "null != serverID.ServerContext");
  803.                 SetStubData(this, serverID.ServerContext.InternalContextID);
  804.             }
  805.         }
  806.        
  807.         protected RealProxy()
  808.         {
  809.         }
  810.     }
  811. }

Developer Fusion