The Labs \ Source Viewer \ SSCLI \ System.Threading \ IUnknownSafeHandle

  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. ** Class:  ExecutionContext
  17. **
  18. **
  19. ** Purpose: Capture Host execution  context for a thread
  20. **
  21. **
  22. ===========================================================*/
  23. namespace System.Threading
  24. {
  25.     using System.Security;
  26.     using System.Runtime.Remoting;
  27.     using System.Runtime.CompilerServices;
  28.     using System.Runtime.Serialization;
  29.     using System.Security.Permissions;
  30.     using System.Runtime.Remoting.Contexts;
  31.     using System.Runtime.Remoting.Messaging;
  32.     using System.Runtime.ConstrainedExecution;
  33.     using System.Runtime.InteropServices;
  34.    
  35.    
  36.    
  37.     internal class HostExecutionContextSwitcher
  38.     {
  39.         internal ExecutionContext executionContext;
  40.         internal HostExecutionContext previousHostContext;
  41.         internal HostExecutionContext currentHostContext;
  42.        
  43.         [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
  44.         public static void Undo(object switcherObject)
  45.         {
  46.             if (switcherObject == null)
  47.                 return;
  48.             // otherwise call the host
  49.             HostExecutionContextManager hostMgr = HostExecutionContextManager.GetCurrentHostExecutionContextManager();
  50.             if (hostMgr != null) {
  51.                 hostMgr.Revert(switcherObject);
  52.             }
  53.         }
  54.     }
  55.    
  56.    
  57.    
  58.     public class HostExecutionContext
  59.     {
  60.         private object state;
  61.        
  62.         protected internal object State {
  63.             get { return state; }
  64.             set { state = value; }
  65.         }
  66.        
  67.         public HostExecutionContext()
  68.         {
  69.         }
  70.        
  71.         public HostExecutionContext(object state)
  72.         {
  73.             this.state = state;
  74.         }
  75.        
  76.         public virtual HostExecutionContext CreateCopy()
  77.         {
  78.             object newState = state;
  79.             if (state is IUnknownSafeHandle) {
  80.                 // Clone the IUnknown handle
  81.                 newState = ((IUnknownSafeHandle)state).Clone();
  82.             }
  83.             return new HostExecutionContext(state);
  84.         }
  85.     }
  86.    
  87.     internal class IUnknownSafeHandle : SafeHandle
  88.     {
  89.         public IUnknownSafeHandle() : base(IntPtr.Zero, true)
  90.         {
  91.         }
  92.        
  93.         public override bool IsInvalid {
  94.             get { return handle == IntPtr.Zero; }
  95.         }
  96.        
  97.         protected override bool ReleaseHandle()
  98.         {
  99.             HostExecutionContextManager.ReleaseHostSecurityContext(this.handle);
  100.             return true;
  101.         }
  102.        
  103.         internal object Clone()
  104.         {
  105.             IUnknownSafeHandle unkSafeHandleCloned = new IUnknownSafeHandle();
  106.             // call into the Hosting API to CLONE the host context
  107.             // stores the output IUnknown in the safehandle,
  108.             if (!IsInvalid) {
  109.                 HostExecutionContextManager.CloneHostSecurityContext(this, unkSafeHandleCloned);
  110.             }
  111.             return unkSafeHandleCloned;
  112.         }
  113.     }
  114.    
  115.    
  116.    
  117.     public class HostExecutionContextManager
  118.     {
  119.         private static bool _fIsHostedChecked;
  120.         private static bool _fIsHosted;
  121.         private static HostExecutionContextManager _hostExecutionContextManager;
  122.        
  123.         [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
  124.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  125.         private static extern bool HostSecurityManagerPresent();
  126.        
  127.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  128.         static internal extern int ReleaseHostSecurityContext(IntPtr context);
  129.        
  130.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  131.         static internal extern int CloneHostSecurityContext(SafeHandle context, SafeHandle clonedContext);
  132.        
  133.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  134.         private static extern int CaptureHostSecurityContext(SafeHandle capturedContext);
  135.        
  136.         [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
  137.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  138.         private static extern int SetHostSecurityContext(SafeHandle context, bool fReturnPrevious, SafeHandle prevContext);
  139.        
  140.         static internal bool CheckIfHosted()
  141.         {
  142.             if (!_fIsHostedChecked) {
  143.                 _fIsHosted = HostSecurityManagerPresent();
  144.                 _fIsHostedChecked = true;
  145.             }
  146.             return _fIsHosted;
  147.         }
  148.        
  149.         // capture Host SecurityContext
  150.         public virtual HostExecutionContext Capture()
  151.         {
  152.             HostExecutionContext context = null;
  153.             // check if we are hosted
  154.             if (CheckIfHosted()) {
  155.                 IUnknownSafeHandle unkSafeHandle = new IUnknownSafeHandle();
  156.                 context = new HostExecutionContext(unkSafeHandle);
  157.                
  158.                 // call into the Hosting API to capture the host context
  159.                 // stores the output IUnknown in the safehandle,
  160.                 CaptureHostSecurityContext(unkSafeHandle);
  161.             }
  162.            
  163.             // otherwise
  164.             return context;
  165.            
  166.         }
  167.         // Set Host SecurityContext
  168.         [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure)]
  169.         public virtual object SetHostExecutionContext(HostExecutionContext hostExecutionContext)
  170.         {
  171.             if (hostExecutionContext == null) {
  172.                 throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_NotNewCaptureContext"));
  173.             }
  174.            
  175.             HostExecutionContextSwitcher switcher = new HostExecutionContextSwitcher();
  176.             ExecutionContext currentExecutionContext = Thread.CurrentThread.ExecutionContext;
  177.            
  178.             switcher.executionContext = currentExecutionContext;
  179.             switcher.currentHostContext = hostExecutionContext;
  180.             switcher.previousHostContext = null;
  181.            
  182.             if (CheckIfHosted()) {
  183.                 if (hostExecutionContext.State is IUnknownSafeHandle) {
  184.                     // setup the previous unknown handle
  185.                     IUnknownSafeHandle unkPrevSafeHandle = new IUnknownSafeHandle();
  186.                     switcher.previousHostContext = new HostExecutionContext(unkPrevSafeHandle);
  187.                    
  188.                     // get the current handle
  189.                     IUnknownSafeHandle unkSafeHandle = (IUnknownSafeHandle)hostExecutionContext.State;
  190.                    
  191.                     // call into the Hosting API to set the host context
  192.                     // second arg indicates whether we want to retrieve the previous context
  193.                     SetHostSecurityContext(unkSafeHandle, true, unkPrevSafeHandle);
  194.                 }
  195.             }
  196.            
  197.             // store the current HostExecutionContext in the ExecutionContext.
  198.             currentExecutionContext.HostExecutionContext = hostExecutionContext;
  199.            
  200.             return switcher;
  201.         }
  202.        
  203.         // this method needs to be reliable
  204.         [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure), ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
  205.         public virtual void Revert(object previousState)
  206.         {
  207.             HostExecutionContextSwitcher hostContextSwitcher = previousState as HostExecutionContextSwitcher;
  208.             if (hostContextSwitcher == null) {
  209.                 throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_CannotOverrideSetWithoutRevert"));
  210.             }
  211.            
  212.             // check Undo is happening on the correct thread
  213.             ExecutionContext executionContext = Thread.CurrentThread.ExecutionContext;
  214.            
  215.             if (executionContext != hostContextSwitcher.executionContext) {
  216.                 throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_CannotUseSwitcherOtherThread"));
  217.             }
  218.             hostContextSwitcher.executionContext = null;
  219.             // Make sure switcher cannot be re-used.
  220.             HostExecutionContext revertFromHostContext = executionContext.HostExecutionContext;
  221.             // if the current host context is not the same as the one in the switcher, then revert is being called out of order
  222.             if (revertFromHostContext != hostContextSwitcher.currentHostContext) {
  223.                 throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_CannotUseSwitcherOtherThread"));
  224.             }
  225.            
  226.             // get the previous host context
  227.             HostExecutionContext revertToHostContext = hostContextSwitcher.previousHostContext;
  228.            
  229.             // now check if we are hosted and revert the context in the host
  230.             if (CheckIfHosted()) {
  231.                 // try restore the previous context as the current context
  232.                 if (revertToHostContext != null && revertToHostContext.State is IUnknownSafeHandle) {
  233.                     IUnknownSafeHandle unkprevSafeHandle = (IUnknownSafeHandle)revertToHostContext.State;
  234.                     // call into the Hosting API to set the host context
  235.                     SetHostSecurityContext(unkprevSafeHandle, false, null);
  236.                 }
  237.             }
  238.            
  239.             //restore the previous host context in the executioncontext
  240.             executionContext.HostExecutionContext = revertToHostContext;
  241.            
  242.         }
  243.        
  244.         static internal HostExecutionContext CaptureHostExecutionContext()
  245.         {
  246.             HostExecutionContext hostContext = null;
  247.             // capture the host execution context
  248.             HostExecutionContextManager hostMgr = HostExecutionContextManager.GetCurrentHostExecutionContextManager();
  249.             if (hostMgr != null) {
  250.                 hostContext = hostMgr.Capture();
  251.             }
  252.             return hostContext;
  253.         }
  254.        
  255.         static internal object SetHostExecutionContextInternal(HostExecutionContext hostContext)
  256.         {
  257.             HostExecutionContextManager hostMgr = HostExecutionContextManager.GetCurrentHostExecutionContextManager();
  258.             object switcher = null;
  259.             if (hostMgr != null) {
  260.                 switcher = hostMgr.SetHostExecutionContext(hostContext);
  261.             }
  262.             return switcher;
  263.         }
  264.        
  265.         // retun the HostExecutionContextManager for the current AppDomain
  266.         [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
  267.         static internal HostExecutionContextManager GetCurrentHostExecutionContextManager()
  268.         {
  269.             // this is called during AppDomainManager initialization, this is a thread safe place
  270.             // to setup the HostExecutionContextManager for the current AppDomain
  271.             if (AppDomainManager.CurrentAppDomainManager != null) {
  272.                
  273.                 return AppDomainManager.CurrentAppDomainManager.HostExecutionContextManager;
  274.             }
  275.             return null;
  276.         }
  277.        
  278.         // retun the HostExecutionContextManager for the current AppDomain
  279.         static internal HostExecutionContextManager GetInternalHostExecutionContextManager()
  280.         {
  281.             if (_hostExecutionContextManager == null) {
  282.                 // setup the HostExecutionContextManager for the current AppDomain
  283.                 BCLDebug.Assert(_hostExecutionContextManager == null, "HostExecutionContextManager should be null");
  284.                 _hostExecutionContextManager = new HostExecutionContextManager();
  285.             }
  286.             return _hostExecutionContextManager;
  287.         }
  288.     }
  289. }

Developer Fusion