AddInControllerImpl.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / AddIn / AddIn / System / Addin / Hosting / AddInControllerImpl.cs / 1305376 / AddInControllerImpl.cs

                            // ==++== 
//
//   Copyright (c) Microsoft Corporation.  All rights reserved.
//
// ==--== 
/*============================================================
** 
** Class:  AddInController 
**
** Purpose: Allows you to shut down an add-in, which may unload 
**     an AppDomain or kill an out-of-process add-in.
**
===========================================================*/
using System; 
using System.Collections.Generic;
using System.Collections.ObjectModel; 
using System.IO; 
using System.Reflection;
using System.Runtime.ConstrainedExecution; 
using System.Runtime.Remoting;
using System.Runtime.Remoting.Lifetime;
using System.Runtime.Serialization;
using System.Security.Permissions; 
using System.Security;
using System.Diagnostics; 
using System.AddIn.Contract; 
using System.AddIn.Pipeline;
using System.Diagnostics.Contracts; 

namespace System.AddIn.Hosting
{
    // The lifetime of an add-in is controlled by remoting's leases, and users 
    // who do essentially ref counting by obtaining a lease.  No one has solved
    // the distributed (cross-machine) garbage collector problem yet, but leases 
    // appear to be the best approximation we currently have. 
    internal sealed class AddInControllerImpl
    { 
        // Maps host add-in views (precisely, instances of host adapters typed
        // as their base type) to the associated add-in controllers.
        private static HAVControllerPair _havList;
        private static readonly Object _havLock = new Object(); 

        //private AppDomain _appDomain; 
        private bool _unloadDomainOnExit; 
        private AddInToken _token;
 
        private AddInEnvironment _addInEnvironment;

        private static int _addInCountSinceLastPrune;
        private const int AddInCountSinceLastPruneLimit = 25; 

        // Note that keeping this reference to the transparentProxy 
        // prevents it from being GC'd in the same sweep as the HAV.  Indeed, it cannot 
        // be GC'd until we remove its HAVController pair.  This is good,
        // since it allows us to call into the TransparentProxy from the finalize method 
        // of LifetimeTokenHandle
        internal IContract _contract;  // Contract or a Transparent Proxy to the contract
        private ActivationWorker _activationWorker;
        private WeakReference _havReference; 

        internal AddInControllerImpl(AddInEnvironment environment, bool unloadDomainOnExit, AddInToken token) 
        { 
            System.Diagnostics.Contracts.Contract.Requires(environment != null);
            System.Diagnostics.Contracts.Contract.Requires(token != null); 

            _unloadDomainOnExit = unloadDomainOnExit;
            _token = token;
 
            _addInEnvironment = environment;
        } 
 
        // Takes a host add-in view (HAV) and maps that to an add-in controller.
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")] 
        internal static AddInController GetAddInController(Object addIn)
        {
            if (addIn == null)
                throw new ArgumentNullException("addIn"); 
            System.Diagnostics.Contracts.Contract.EndContractBlock();
 
            AddInControllerImpl controllerImpl = FindController(addIn, false); 

            //return new wrapper 
            if (controllerImpl != null)
            {
                // Try and increase the ref count on the addin.  If we fail, perhaps
                // because the user already called Dispose() on the HVA, that's OK.  Still allow 
                // them to use the AddInController to examine the AddInToken
                ContractHandle handle = null; 
                try 
                {
                     handle = new ContractHandle(controllerImpl._contract); 
                }
                catch (Exception) {}
                return new AddInController(controllerImpl, addIn, handle);
            } 

            throw new ArgumentException(Res.ControllerNotFound); 
        } 

        // Find the controller given the HAV (addIn), optionally also removing it. 
        // This code also removes any stale HAVControllerPairs that it finds, as
        // may happen when a HAV is garbage collected.
        private static AddInControllerImpl FindController(Object addIn, bool remove)
        { 
            System.Diagnostics.Contracts.Contract.Requires(addIn != null);
 
            lock (_havLock) 
            {
                HAVControllerPair current = _havList; 
                HAVControllerPair last = null;
                while(current != null)
                {
                    Object o = current._HAV.Target; 
                    if (o == null)
                    { 
                        // this one has been GC'd.  Clean up the WR 
                        if (last == null)
                        { 
                            _havList = current._next;
                            break;
                        }
                        else 
                        {
                            last._next = current._next; 
                            current = current._next; 
                            continue;
                        } 
                    }
                    else
                    {
                        if (addIn.Equals(o)) 
                        {
                            AddInControllerImpl value = current._controller; 
                            if (remove) 
                            {
                                if (last == null) 
                                    _havList = current._next;
                                else
                                    last._next = current._next;
                            } 
                            return value;
                        } 
                    } 

                    last = current; 
                    current = current._next;
                }
            }
            return null; 
        }
 
        // Requires the HAV and the transparent proxy to the add-in adapter, 
        // which implements System.AddIn.Contract.IContract.
        internal void AssociateWithHostAddinView(Object hostAddinView, IContract contract) 
        {
            System.Diagnostics.Contracts.Contract.Requires(hostAddinView != null);
            _contract = contract;
 
            // add weak reference on the HAV to our list
            _havReference = new WeakReference(hostAddinView); 
            lock (_havLock) 
            {
                HAVControllerPair havRef = new HAVControllerPair(hostAddinView, this); 
                havRef._next = _havList;
                _havList = havRef;

                // clean up the list every so often 
                _addInCountSinceLastPrune++;
                if (_addInCountSinceLastPrune == AddInCountSinceLastPruneLimit) 
                { 
                    // searching for a non-exiting addin will have the desired effect
                    // of pruning the list of any stale references. 
                    FindController(new Object(), false);
                    _addInCountSinceLastPrune = 0;
                }
            } 
        }
 
        internal ActivationWorker ActivationWorker { 
            set {
                System.Diagnostics.Contracts.Contract.Requires(value != null); 
                _activationWorker = value;
            }
        }
 
        //
        // 
        // 
        //
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2103:ReviewImperativeSecurity", Justification = "Reviewed"), 
         System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2001:AvoidCallingProblematicMethods", MessageId = "System.Reflection.Assembly.LoadFrom", Justification = "LoadFrom was designed for addins")]
        [System.Security.SecuritySafeCritical]
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2128:SecurityTransparentCodeShouldNotAssert", Justification = "This is a SecurityRules.Level1 assembly, in which this rule is being incorrectly applied")]
        internal IContract GetContract() 
        {
            if (_contract != null) 
                return _contract; 

            // in direct connect, the contract has not been created.  Create it now. 
            Object hav = _havReference.Target;
            if (hav == null)
                throw new InvalidOperationException(Res.AddInNoLongerAvailable);
 
            // Assert permission to the contracts, AddInSideAdapters, AddInViews and specific Addin directories only.
            PermissionSet permissionSet = new PermissionSet(PermissionState.None); 
            permissionSet.AddPermission(new FileIOPermission(FileIOPermissionAccess.Read | FileIOPermissionAccess.PathDiscovery, 
                Path.Combine(_token.PipelineRootDirectory, AddInStore.ContractsDirName)));
            permissionSet.AddPermission(new FileIOPermission(FileIOPermissionAccess.Read | FileIOPermissionAccess.PathDiscovery, 
                Path.Combine(_token.PipelineRootDirectory, AddInStore.AddInAdaptersDirName)));
            permissionSet.Assert();

            Assembly.LoadFrom(_token._contract.Location); 
            Assembly addinAdapterAssembly = Assembly.LoadFrom(_token._addinAdapter.Location);
            CodeAccessPermission.RevertAssert(); 
 
            // Create the AddIn adapter for the addin
            ActivationWorker worker = new ActivationWorker(_token); 
            _contract = worker.CreateAddInAdapter(hav, addinAdapterAssembly);
            return _contract;
        }
 
        // 
        //  
        //  
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2001:AvoidCallingProblematicMethods", MessageId = "System.GC.Collect", Justification = "Recommended by GC team")]
        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] 
        public void Shutdown()
        {
            // Disables usage of the add-in, by breaking the pipeline.
            // Also, if we own the appdomain, we unload it. 
            lock (this)  // Ensure multiple threads racing on Shutdown don't collide.
            { 
                AddInEnvironment environment = _addInEnvironment; 
                if (environment != null) {
                    try { 
                        if (_contract != null) {

                            Object hav = _havReference.Target;
                            IDisposable disposableHAV = hav as IDisposable; 
                            if (disposableHAV != null)
                            { 
                                try 
                                {
                                    disposableHAV.Dispose(); 
                                }
                                catch (AppDomainUnloadedException e)
                                {
                                    Log(e.ToString()); 
                                }
                                catch (RemotingException re) 
                                { 
                                    Log(re.ToString());
                                } 
                                catch (SerializationException se)
                                {
                                    Log(se.ToString());
                                } 
                            }
 
                            IDisposable disposableContract = _contract as IDisposable; 
                            if (disposableContract != null)
                            { 
                                try
                                {
                                    disposableContract.Dispose();
                                } 
                                catch (AppDomainUnloadedException e)
                                { 
                                    Log(e.ToString()); 
                                }
                                catch (RemotingException re) 
                                {
                                    Log(re.ToString());
                                }
                                catch (SerializationException se) 
                                {
                                    Log(se.ToString()); 
                                } 
                            }
                            _contract = null; 
                        }

                        if (_activationWorker != null) {
                            // Unhook an assembly resolve event in the target appdomain. 
                            // However, if one of the adapters implemented IDisposable and cleaned
                            // up the appropriate lifetime tokens, this appdomain may be unloading 
                            // already (we launch another thread to do this, so we are guaranteed 
                            // to have a benign race condition).  We should catch an
                            // AppDomainUnloadedException here. 
                            try
                            {
                                _activationWorker.Dispose();
                            } 
                            catch (AppDomainUnloadedException) { }
                            catch (RemotingException) { } 
                            catch (SerializationException) { } 

                            _activationWorker = null; 
                        }
                    }
                    finally {
                        if (_unloadDomainOnExit) { 
                            // AppDomain.Unload will block until we have finalized all
                            // objects within the appdomain.  Also, this may already 
                            // have been unloaded. 
                            try {
                                environment.UnloadAppDomain(); 
                            }
                            catch (AppDomainUnloadedException) { }
                            catch (RemotingException) { }
 
                            // Using the transparent proxy will now cause exceptions,
                            // as managed threads are not allowed to enter this appdomain. 
                        } 
                    }
                    _addInEnvironment = null; 

                    // eagerly remove from list
                    lock (_havLock)
                    { 
                        Object addin = _havReference.Target;
                        if (addin != null) 
                            FindController(addin, true); 
                    }
 
                    // The perf team recommends doing a GC after a large amount of memory has
                    // been dereferenced.  We wait for the finalizers to complete first
                    // becase some references in the addin are not released until finalization.
                    // Also, if an addin is buggy and causes the finalizer thread to hang, 
                    // waiting here makes it fail deterministically.
                    System.GC.WaitForPendingFinalizers(); 
                    System.GC.Collect(); 

                } // end if domain != null 
                else {
                    throw new InvalidOperationException(Res.AppDomainNull);
                }
            } 
        }
 
        // This will not be usable for OOP scenarios. 
        internal AppDomain AppDomain {
            get { 
                if (_addInEnvironment == null)
                    throw new ObjectDisposedException("appdomain");
                return _addInEnvironment.AppDomain;
            } 
        }
 
        internal AddInToken Token { 
            get {
                return _token; 
            }
        }

        internal AddInEnvironment AddInEnvironment 
        {
            get { 
                return _addInEnvironment; 
            }
        } 

        private static void Log(String message)
        {
            Debugger.Log(0, "AddInController", message); 
        }
 
        internal sealed class HAVControllerPair 
        {
            internal WeakReference _HAV; 
            internal AddInControllerImpl _controller;
            internal HAVControllerPair _next;

            public HAVControllerPair(Object hav, AddInControllerImpl controller) 
            {
                _HAV = new WeakReference(hav); 
                _controller = controller; 
            }
        } 
    }
}

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