AddInActivator.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 / fx / src / AddIn / AddIn / System / Addin / Hosting / AddInActivator.cs / 1305376 / AddInActivator.cs

                            // ==++== 
//
//   Copyright (c) Microsoft Corporation.  All rights reserved.
//
// ==--== 
/*============================================================
** 
** Class:  AddInActivator 
**
** Purpose: Allows you to create an instance of an add-in, 
**     in another AppDomain or process.
**
===========================================================*/
using System; 
using System.AddIn.Contract;
using System.AddIn.MiniReflection; 
using System.AddIn.Pipeline; 
using System.Collections;
using System.Collections.Generic; 
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.IO; 
using System.Globalization;
using System.Reflection; 
using System.Reflection.Emit; 
using System.Runtime.Remoting;
using System.Security; 
using System.Security.Permissions;
using System.Security.Policy;
using System.Text;
using System.Threading; 
using System.Diagnostics.Contracts;
 
namespace System.AddIn.Hosting 
{
    internal static class AddInActivator 
    {
        internal static T Activate(AddInToken token, AddInSecurityLevel level)
        {
            if (token == null) 
                throw new ArgumentNullException("token");
            System.Diagnostics.Contracts.Contract.EndContractBlock(); 
 
            // the name for the addin makes a good name for the appdomain
            return Activate(token, level, token.Name); 
        }

        // Creates a new AppDomain with the given security level & the specified friendly name.
        // Then creates an instance of the add-in within that appdomain, handing back the host 
        // add-in view.  We'll also have to create an AddInControllerImpl to track & unload this add-in.
        internal static T Activate(AddInToken token, AddInSecurityLevel level, String appDomainName) 
        { 
            if (token == null)
                throw new ArgumentNullException("token"); 
            if (appDomainName == null)
                throw new ArgumentNullException("appDomainName");
            System.Diagnostics.Contracts.Contract.EndContractBlock();
 
            PermissionSet permissionSet = GetPermissionSetForLevel(level);
            return Activate(token, permissionSet, appDomainName); 
        } 

        //  
        // 
        // 
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification="Reviewed")]
        [System.Security.SecuritySafeCritical] 
        internal static PermissionSet GetPermissionSetForLevel(AddInSecurityLevel level)
        { 
            if (AddInSecurityLevel.Internet > level || level > AddInSecurityLevel.Host) 
                throw new ArgumentOutOfRangeException("level");
            System.Diagnostics.Contracts.Contract.EndContractBlock(); 

            if (level == AddInSecurityLevel.Host)
            {
                return AppDomain.CurrentDomain.PermissionSet; 
            }
            else 
            { 
                // Get a permission set for all non-GAC'ed code within the AD.
                Evidence sandboxEvidence = new Evidence(); 

                if (level == AddInSecurityLevel.Internet)
                {
                    sandboxEvidence.AddHostEvidence(new Zone(SecurityZone.Internet)); 
                }
                else if (level == AddInSecurityLevel.Intranet) 
                { 
                    sandboxEvidence.AddHostEvidence(new Zone(SecurityZone.Intranet));
                } 
                else if (level == AddInSecurityLevel.FullTrust)
                {
                    sandboxEvidence.AddHostEvidence(new Zone(SecurityZone.MyComputer));
                } 
                else if (level != AddInSecurityLevel.Internet)
                { 
                    throw new ArgumentOutOfRangeException("level"); 
                }
 

                return SecurityManager.GetStandardSandbox(sandboxEvidence);
            }
        } 

        // Assert full trust because we are seeing a full-trust demand here when there is 
        // an AppDomainManager configured that has an internal constructor 
        [System.Security.SecurityCritical]
        [PermissionSet(SecurityAction.Assert, Unrestricted=true)] 
        private static AppDomain CreateDomain(AddInToken token, PermissionSet permissionSet, String appDomainName)
        {
            AppDomainSetup setup = new AppDomainSetup();
            setup.ApplicationBase = Path.GetDirectoryName(token._addin.Location); 
            setup.ConfigurationFile = token._addin.Location + ".config";
            Assembly sysAddIn = typeof(AddInActivator).Assembly; 
            // 
            AppDomain domain = AppDomain.CreateDomain(appDomainName,
                AppDomain.CurrentDomain.Evidence, setup, permissionSet, 
                CreateStrongName(sysAddIn));  // Grant full trust to System.AddIn.dll
            // Ensure we load System.AddIn.dll in this new AD.
            domain.Load(sysAddIn.FullName);
            return domain; 
        }
 
        [System.Security.SecuritySafeCritical] 
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2129:SecurityTransparentCodeShouldNotReferenceNonpublicSecurityCriticalCode", Justification = "This is a SecurityRules.Level1 assembly, in which this rule is being incorrectly applied")]
        private static T Activate(AddInToken token, PermissionSet permissionSet, String appDomainName) 
        {
            // Don't let them create an appdomain that elevates privileges
            permissionSet.Demand();
 
            AppDomain domain = null;
            try 
            { 
                domain = CreateDomain(token, permissionSet, appDomainName);
 
                AddInEnvironment environment = new AddInEnvironment(domain, true);
                AddInControllerImpl controller = new AddInControllerImpl(environment, true, token);
                return ActivateInAppDomain(token, domain, controller, true);
            } 
            catch
            { 
                // Don't leak the domain. 
                if (domain != null)
                { 
                    try {
                        Utils.UnloadAppDomain(domain);
                    }
                    catch (AppDomainUnloadedException){} 
                }
                throw; 
            } 
        }
 
        internal static T Activate(AddInToken token, AppDomain target)
        {
            if (token == null)
                throw new ArgumentNullException("token"); 
            if (target == null)
                throw new ArgumentNullException("target"); 
            System.Diagnostics.Contracts.Contract.EndContractBlock(); 

            AddInEnvironment environment = new AddInEnvironment(target); 
            AddInControllerImpl controller = new AddInControllerImpl(environment, false, token);
            return ActivateInAppDomain(token, target, controller, false);
        }
 
        internal static T Activate(AddInToken token, PermissionSet permissionSet)
        { 
            if (token == null) 
                throw new ArgumentNullException("token");
            if (permissionSet == null) 
                throw new ArgumentNullException("permissionSet");
            System.Diagnostics.Contracts.Contract.EndContractBlock();

            return Activate(token, permissionSet, token.Name); 
        }
 
        // OOP Activation 
        // 
        //  
        // 
        // 
        // 
        //  
        [System.Security.SecuritySafeCritical]
        internal static T Activate(AddInToken token, AddInProcess process, PermissionSet permissionSet) 
        { 
            if (token == null)
                throw new ArgumentNullException("token"); 
            if (permissionSet == null)
                throw new ArgumentNullException("permissionSet");
            if (process == null)
                throw new ArgumentNullException("process"); 
            System.Diagnostics.Contracts.Contract.EndContractBlock();
 
            // check that they have ExecutionPermission.  Otherwise OOP remoting fails 
            // by shutting down the pipe, leaving the user scratching his head.
            if (!permissionSet.IsUnrestricted()) 
            {
                SecurityPermission p = (SecurityPermission)permissionSet.GetPermission(typeof(SecurityPermission));
                SecurityPermissionFlag requiredFlags = SecurityPermissionFlag.Execution;
                if (p == null || (p.Flags & requiredFlags) != requiredFlags) 
                    throw new ArgumentException(Res.NeedSecurityFlags);
            } 
 
            RemotingHelper.InitializeClientChannel();
 
            AddInServer addInServer = process.GetAddInServer();

            AddInServerWorker addInServerWorker = addInServer.CreateDomain(token, permissionSet);
            AddInEnvironment fullEnvironment = new AddInEnvironment(process, addInServerWorker); 

            return ActivateOutOfProcess(token, fullEnvironment, true); 
        } 

        internal static T Activate(AddInToken token, AddInProcess process, AddInSecurityLevel level) 
        {
            PermissionSet permissionSet = GetPermissionSetForLevel(level);
            return Activate(token, process, permissionSet);
        } 

        // Activation in an existing appdomain, either in-process or out-of-process 
        internal static T Activate(AddInToken token, AddInEnvironment environment) 
        {
            if (environment == null) 
                throw new ArgumentNullException("environment");
            System.Diagnostics.Contracts.Contract.EndContractBlock();

            if (environment.Process.IsCurrentProcess) 
            {
                AddInControllerImpl controller = new AddInControllerImpl(environment, false, token); 
                return ActivateInAppDomain(token, environment.AppDomain, controller, false); 
            }
            else 
            {
                return ActivateOutOfProcess(token, environment, false);
            }
        } 

        // helper method 
        // 
        private static T ActivateOutOfProcess(AddInToken token, AddInEnvironment environment, bool weOwn)
        { 
            ActivationWorker worker;
            IContract contract = environment.AddInServerWorker.Activate(token, out worker);

            AddInControllerImpl controller = new AddInControllerImpl(environment, weOwn, token); 
            controller.ActivationWorker = worker;
 
            T hav = AdaptToHost(token, contract); 
            if (weOwn)
                environment.AddInServerWorker.SetAppDomainOwner(contract); 

            // Add this HAV and add-in controller to our list of currently
            // non-disposed add-ins.
            controller.AssociateWithHostAddinView(hav, contract); 
            return hav;
        } 
 

        // Create a worker class in the remote appdomain, create the add-in & 
        // add-in adapter in the remote appdomain, then create the host adapter
        // in this appdomain, passing in a transparent proxy to the user's contract
        // implementation (which is really an instance of the add-in adapter).
        // The host adapter is a subclass of the host add-in view, which is our 
        // return value (T).  Also, associate the host add-in view with the add-in
        // controller. 
        //  
        // 
        //  
        // 
        // 
        // 
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2103:ReviewImperativeSecurity", Justification = "Reviewed"), 
         System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "Reviewed"),
         System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2001:AvoidCallingProblematicMethods", MessageId = "System.Reflection.Assembly.LoadFrom", Justification = "LoadFrom was designed for addin loading")] 
        [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")]
        private static T ActivateInAppDomain(AddInToken pipeline, AppDomain domain, AddInControllerImpl controller, bool weOwn) 
        {
            ContractComponent contract = pipeline._contract;
            HostAdapter hostAdapter = pipeline._hostAdapter;
 
            bool usingHostAppDomain = domain == AppDomain.CurrentDomain;
 
            //begin direct connect code 
            if (AddInToken.EnableDirectConnect && !weOwn && usingHostAppDomain)
            { 
                Type havType = typeof(T);
                TypeInfo havTypeInfo = new TypeInfo(havType);

                if (pipeline._addinBase.CanDirectConnectTo(havTypeInfo)) 
                {
                    // Connect directly for best performance. 
                    // Assert permission to the specific Addin directory only. 
                    PermissionSet permissionSet = new PermissionSet(PermissionState.None);
                    permissionSet.AddPermission(new FileIOPermission(FileIOPermissionAccess.Read | FileIOPermissionAccess.PathDiscovery, 
                        Path.GetDirectoryName(pipeline._addin.Location)));
                    permissionSet.Assert();

                    Assembly addInAssembly = Assembly.LoadFrom(pipeline._addin.Location); 
                    //
                    Type addinType = addInAssembly.GetType(pipeline._addin.TypeInfo.FullName, true); 
                    Object addIn = addinType.GetConstructor(new Type[0]).Invoke(new Object[0]); 
                    System.Diagnostics.Contracts.Contract.Assert(addIn != null, "Bypass couldn't create the add-in");
 
                    // remember the addin directly as the HAV.  Set the contract to null.
                    controller.AssociateWithHostAddinView(addIn, null);

                    return (T)addIn; 
                }
            } 
            //end direct connect code 

            // Use Activator.CreateInstance instead of AppDomain.CreateInstanceAndUnwrap 
            // because Activator will do the appropriate security asserts in the
            // remote appdomain.
            Type t = typeof(ActivationWorker);
            Object[] args = new Object[] { pipeline }; 
            ObjectHandle objHandle = Activator.CreateInstance(domain, t.Assembly.FullName, t.FullName,
                false, BindingFlags.Instance | BindingFlags.NonPublic, null, 
                args, null, null); 
            ActivationWorker activationWorker = (ActivationWorker) objHandle.Unwrap();
            activationWorker.UsingHostAppDomain = usingHostAppDomain; 

            System.AddIn.Contract.IContract addInContract = null;
            try
            { 
                addInContract = activationWorker.Activate();
            } 
            catch (Exception ex) 
            {
                CheckForDuplicateAssemblyProblems(pipeline, ex); 
                throw;
            }

            if (weOwn) 
                domain.SetData(ContractHandle.s_appDomainOwner, addInContract);
 
            controller.ActivationWorker = activationWorker; 
            T hav = AdaptToHost(pipeline, addInContract);
            controller.AssociateWithHostAddinView(hav, addInContract); 

            return hav;
        }
 

        //  
        //  
        // 
        //  
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification="Reviewed")]
        [System.Security.SecuritySafeCritical]
        private static T AdaptToHost(AddInToken pipeline, IContract addInContract)
        { 
            if (addInContract == null)
                throw new ArgumentNullException("addInContract"); 
            System.Diagnostics.Contracts.Contract.EndContractBlock(); 

            ContractComponent contract = pipeline._contract; 
            HostAdapter hostAdapter = pipeline._hostAdapter;

            Type hostAdapterType;
            Type contractType; 
            LoadContractAndHostAdapter(contract, hostAdapter, out contractType, out hostAdapterType);
 
            int? temporaryToken = null; 
            try
            { 
                temporaryToken = addInContract.AcquireLifetimeToken();

                // This assembly resolve event exists to:
                //    1) To upgrade the contract assembly from the LoadFrom context to 
                //       the default loader context
                ResolverHelper resolver = new ResolverHelper(pipeline); 
                ResolveEventHandler assemblyResolver = new ResolveEventHandler(resolver.ResolveAssemblyForHostAdapter); 
                AppDomain.CurrentDomain.AssemblyResolve += assemblyResolver;
 
                // Create the Host Adapter, which is a subclass of the Host Add-In View.
                // Pass the contract implementation to this constructor, using a
                // transparent proxy to the real type.  Detect common errors here.
                InvokerDelegate myInvokerDelegate = CreateConsInvoker(hostAdapterType, contractType); 

                T hav; 
                try 
                {
                    hav = (T)myInvokerDelegate(addInContract); 
                }
                catch (ArgumentException e)
                {
                    CheckForLoaderContextProblems(contract, pipeline._addinAdapter, e); 
                    throw;
                } 
                finally 
                {
                    AppDomain.CurrentDomain.AssemblyResolve -= assemblyResolver; 
                }

                return hav;
            } 
            finally
            { 
                if (temporaryToken != null && addInContract != null) 
                    addInContract.RevokeLifetimeToken((int)temporaryToken);
            } 
        }

        // Delegate used to invoke the constructor of the adapter, providing a contract, and return
        // the adapter. 
        internal delegate Object InvokerDelegate(Object contract);
 
        //  
        // 
        //  
        /// This method is used instead of the usual reflection Invoke on the constructor because
        /// we need to Assert the ability to see the internal constructor, but we don't
        /// want that Assert to carry over into the user code inside the constructor.  Reflection.Emit(LWCG)
        /// allows us to "see" the internal members first and then invoke them later in a separate action. 
        [System.Security.SecuritySafeCritical]
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2129:SecurityTransparentCodeShouldNotReferenceNonpublicSecurityCriticalCode", Justification = "This is a SecurityRules.Level1 assembly, in which this rule is being incorrectly applied")] 
        internal static InvokerDelegate CreateConsInvoker(Type targetType, Type argType) 
        {
            ConstructorInfo havCtor = targetType.GetConstructor( 
                BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance,
                null, new Type[]{argType}, null);

            Type[] methodArgs = new Type[]{typeof(Object)}; 
            DynamicMethod invoker = AssertAndCreateInvoker(targetType, argType, methodArgs, havCtor);
 
            return (InvokerDelegate)invoker.CreateDelegate(typeof(InvokerDelegate)); 
        }
 

        /// We assert full trust because that is needed in scenarios where the caller is lower
        /// trust than the callee assembly.  The demand happens when the call is jitted, but
        /// the stack is captured when the DynamicMethod is created. 
        [PermissionSet(SecurityAction.Assert, Unrestricted=true)]
        [System.Security.SecurityCritical] 
        private static DynamicMethod AssertAndCreateInvoker(Type targetType, Type argType,  Type[] methodArgs, ConstructorInfo havCtor) 
        {
            // As a workaround to a red bits bug that leaks memory, we don't associate this 
            // DM with an assembly.  Instead, we host it anonymously, and we need to assert
            // full trust.
            DynamicMethod invoker = new DynamicMethod(targetType.Name + "_ConstructorInvoker", // name, only usefult for debugging
                                                      typeof(Object),  // return type 
                                                      methodArgs, // parameterTypes
                                                      true); // skip visibility 
            ILGenerator il = invoker.GetILGenerator(); 
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Castclass, argType); // need to cast Object to the specific Contract type expected by the constructor 
            il.Emit(OpCodes.Newobj, havCtor); // invoke the constructor
            il.Emit(OpCodes.Ret);

            return invoker; 
        }
 
        //  
        // 
        //  
        [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 static void LoadContractAndHostAdapter(ContractComponent contract, HostAdapter hostAdapter,
                out Type contractType, out Type hostAdapterType) 
        { 
            PermissionSet assertSet = new PermissionSet(PermissionState.None);
            assertSet.AddPermission(new FileIOPermission(FileIOPermissionAccess.Read | FileIOPermissionAccess.PathDiscovery, hostAdapter.Location)); 
            assertSet.AddPermission(new FileIOPermission(FileIOPermissionAccess.Read | FileIOPermissionAccess.PathDiscovery, contract.Location));
            assertSet.Assert();

            // Explicitly load the host adapter & contract first, using LoadFrom 
            // to ensure they are loaded in the same loader context.
            Assembly hostAdapterAssembly = Assembly.LoadFrom(hostAdapter.Location); 
            Assembly contractAssembly = Assembly.LoadFrom(contract.Location); 

            hostAdapterType = hostAdapterAssembly.GetType(hostAdapter.TypeInfo.FullName, true); 
            contractType = contractAssembly.GetType(contract.TypeInfo.FullName, true);
        }

        // This method is used to re-adapt a given addin to another HAV 
        // 
        //  
        //  
        // 
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification="Reviewed")] 
        [System.Security.SecuritySafeCritical]
        internal static T ActivateHostAdapter(PartialToken pipeline, IContract addIn)
        {
            if (pipeline == null) 
                throw new ArgumentNullException("pipeline");
            if (addIn == null) 
                throw new ArgumentNullException("addIn"); 
            System.Diagnostics.Contracts.Contract.EndContractBlock();
 
            ContractComponent contract = pipeline._contract;
            HostAdapter hostAdapter = pipeline._hostAdapter;

            Type hostAdapterType; 
            Type contractType;
            LoadContractAndHostAdapter(contract, hostAdapter, out contractType, out hostAdapterType); 
 
            // This assembly resolve event exists to:
            //    1) To upgrade the contract assembly from the LoadFrom context to 
            //       the default loader context
            ResolverHelper resolver = new ResolverHelper(contract);
            ResolveEventHandler assemblyResolver = new ResolveEventHandler(resolver.ResolveAssemblyForHostAdapter);
            AppDomain.CurrentDomain.AssemblyResolve += assemblyResolver; 

            T hav; 
 
            InvokerDelegate myInvokerDelegate = CreateConsInvoker(hostAdapterType, contractType);
            try 
            {
                hav = (T)myInvokerDelegate(addIn);
            }
            catch (ArgumentException e) 
            {
                CheckForLoaderContextProblems(contract, pipeline._addinAdapter, e); 
                throw; 
            }
            finally 
            {
                AppDomain.CurrentDomain.AssemblyResolve -= assemblyResolver;
            }
 
            return hav;
        } 
 

        private static void CheckForDuplicateAssemblyProblems(AddInToken pipeline, Exception inner) 
        {
            Collection warnings = new Collection();
            bool duplicates = pipeline.HasDuplicatedAssemblies(null, warnings);
            if (duplicates) 
            {
                String[] s = new String[warnings.Count]; 
                warnings.CopyTo(s, 0); 
                throw new InvalidOperationException(String.Join("\n", s), inner);
            } 
        }

        // Detects two somewhat easy to hit user bugs, where the contract assembly
        // is loaded twice in different loader contexts, or where the add-in adapter 
        // has been loaded in the host's assembly.  If either of these happens,
        // then the transparent proxy will not be castable to the interface type, 
        // and the remoting code will attempt to load the addin adapter's 
        // type in the host's appdomain.
        // We explicitly do not allow the add-in adapter's assembly to leak 
        // into this appdomain.  If the contract assembly exists in the same
        // directory as the application, or in potentially other locations, it may
        // get loaded twice in different loader contexts by the CLR V2's loader.
        // This took about a week to debug, with experts from all the affected areas. 
        private static void CheckForLoaderContextProblems(ContractComponent contract, AddInAdapter addinAdapter, Exception inner)
        { 
            String contractAsmName = contract.TypeInfo.AssemblyName; 
            String addinAdapterAsmName = addinAdapter.TypeInfo.AssemblyName;
 
            List contracts = new List();
            List addinAdapters = new List();
            foreach (Assembly a in AppDomain.CurrentDomain.GetAssemblies()) {
                String aName = a.GetName().FullName; 
                if (aName == contractAsmName)
                    contracts.Add(a); 
                if (aName == addinAdapterAsmName) 
                    addinAdapters.Add(a);
            } 

            if (addinAdapters.Count > 0) {
                StringBuilder locations = new StringBuilder();
                foreach (Assembly a in addinAdapters) { 
                    locations.Append(Environment.NewLine);
                    locations.Append(a.CodeBase); 
                } 

                Exception e = new InvalidOperationException( 
                    String.Format(CultureInfo.CurrentCulture, Res.AddInAdapterLoadedInWrongAppDomain,
                        addinAdapter.TypeInfo.AssemblyName, addinAdapter.Location, locations.ToString()), inner);
                e.Data["Incorrectly loaded add-in adapters"] = addinAdapters;
                e.Data["Expected adapter location"] = addinAdapter.Location; 
                if (contracts.Count > 1)
                    e.Data["Duplicate Contracts"] = contracts; 
                throw e; 
            }
 
            if (contracts.Count > 1) {
                StringBuilder locations = new StringBuilder();
                foreach (Assembly a in contracts)
                { 
                    locations.Append(Environment.NewLine);
                    locations.Append(a.CodeBase); 
                } 

                Exception e = new InvalidOperationException( 
                    String.Format(CultureInfo.CurrentCulture, Res.ContractAssemblyLoadedMultipleTimes,
                        contract.TypeInfo.AssemblyName, contract.Location, locations.ToString()), inner);
                e.Data["Incorrectly loaded contracts"] = contracts;
                e.Data["Expected contract location"] = contract.Location; 
                throw e;
            } 
            else { 
                // If you're seeing this in a debugger on V2 of the CLR, make sure you hook the assembly resolve event.
                // Otherwise, see if there was an ArgumentException thrown from an HAV's constructor. 
                System.Diagnostics.Contracts.Contract.Assert(false, "Did the AddIn Model upgrade the contract to the default loader context using an assembly resolve event?  Either that, or your HAV's constructor threw an ArgumentException");
            }
        }
 
        internal sealed class ResolverHelper
        { 
            private ContractComponent _contract; 

            internal ResolverHelper(AddInToken pipeline) : this(pipeline._contract) 
            {
            }

            internal ResolverHelper(ContractComponent contract) 
            {
                _contract = contract; 
            } 

            internal Assembly ResolveAssemblyForHostAdapter(Object sender, ResolveEventArgs args) 
            {
                System.Diagnostics.Contracts.Contract.Assert(_contract != null);

                String assemblyRef = args.Name; 
                //Console.WriteLine("ResolveAssemblyForHostAdapter: {0}", assemblyRef);
 
                // We load the contract assembly in the LoadFrom context, but we 
                // need it in the default loader context.  In the V2 loader, we'll
                // need to explicitly return the currently loaded contract assembly 
                // here, which will "upgrade" the assembly from LoadFrom to default.
                Assembly a = Utils.FindLoadedAssemblyRef(assemblyRef);
                if (a != null)
                    return a; 

                // look in the contracts folder, in case there is a second contract there 
                // this HostAdapter depends on. 
                List dirsToLookIn = new List();
                string contractsDir = Path.GetDirectoryName(_contract.Location); 
                dirsToLookIn.Add(contractsDir);

                return Utils.LoadAssemblyFrom(dirsToLookIn, assemblyRef);
            } 
        }
 
        ///  
        /// Create a StrongName that matches a specific assembly
        ///  
        /// 
        /// if  is null
        /// 
        ///  
        /// if  does not represent a strongly named assembly
        ///  
        /// Assembly to create a StrongName for 
        /// A StrongName that matches the given assembly
        //  
        // 
        // 
        [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 static StrongName CreateStrongName(Assembly assembly)
        { 
            System.Diagnostics.Contracts.Contract.Requires(assembly != null); 

            // Since there is no managed API for finding the GAC path, I 
            // assert path discovery for all local files.
            FileIOPermission permission = new FileIOPermission(PermissionState.None);
            permission.AllLocalFiles = FileIOPermissionAccess.PathDiscovery;
            permission.Assert(); 
            AssemblyName assemblyName = assembly.GetName();
            CodeAccessPermission.RevertAssert(); 
 
            // get the public key blob
            byte[] publicKey = assemblyName.GetPublicKey(); 
            if (publicKey == null || publicKey.Length == 0)
                throw new InvalidOperationException(Res.NoStrongName);

            StrongNamePublicKeyBlob keyBlob = new StrongNamePublicKeyBlob(publicKey); 

            // and create the StrongName 
            return new StrongName(keyBlob, assemblyName.Name, assemblyName.Version); 
        }
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// ==++== 
//
//   Copyright (c) Microsoft Corporation.  All rights reserved.
//
// ==--== 
/*============================================================
** 
** Class:  AddInActivator 
**
** Purpose: Allows you to create an instance of an add-in, 
**     in another AppDomain or process.
**
===========================================================*/
using System; 
using System.AddIn.Contract;
using System.AddIn.MiniReflection; 
using System.AddIn.Pipeline; 
using System.Collections;
using System.Collections.Generic; 
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.IO; 
using System.Globalization;
using System.Reflection; 
using System.Reflection.Emit; 
using System.Runtime.Remoting;
using System.Security; 
using System.Security.Permissions;
using System.Security.Policy;
using System.Text;
using System.Threading; 
using System.Diagnostics.Contracts;
 
namespace System.AddIn.Hosting 
{
    internal static class AddInActivator 
    {
        internal static T Activate(AddInToken token, AddInSecurityLevel level)
        {
            if (token == null) 
                throw new ArgumentNullException("token");
            System.Diagnostics.Contracts.Contract.EndContractBlock(); 
 
            // the name for the addin makes a good name for the appdomain
            return Activate(token, level, token.Name); 
        }

        // Creates a new AppDomain with the given security level & the specified friendly name.
        // Then creates an instance of the add-in within that appdomain, handing back the host 
        // add-in view.  We'll also have to create an AddInControllerImpl to track & unload this add-in.
        internal static T Activate(AddInToken token, AddInSecurityLevel level, String appDomainName) 
        { 
            if (token == null)
                throw new ArgumentNullException("token"); 
            if (appDomainName == null)
                throw new ArgumentNullException("appDomainName");
            System.Diagnostics.Contracts.Contract.EndContractBlock();
 
            PermissionSet permissionSet = GetPermissionSetForLevel(level);
            return Activate(token, permissionSet, appDomainName); 
        } 

        //  
        // 
        // 
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification="Reviewed")]
        [System.Security.SecuritySafeCritical] 
        internal static PermissionSet GetPermissionSetForLevel(AddInSecurityLevel level)
        { 
            if (AddInSecurityLevel.Internet > level || level > AddInSecurityLevel.Host) 
                throw new ArgumentOutOfRangeException("level");
            System.Diagnostics.Contracts.Contract.EndContractBlock(); 

            if (level == AddInSecurityLevel.Host)
            {
                return AppDomain.CurrentDomain.PermissionSet; 
            }
            else 
            { 
                // Get a permission set for all non-GAC'ed code within the AD.
                Evidence sandboxEvidence = new Evidence(); 

                if (level == AddInSecurityLevel.Internet)
                {
                    sandboxEvidence.AddHostEvidence(new Zone(SecurityZone.Internet)); 
                }
                else if (level == AddInSecurityLevel.Intranet) 
                { 
                    sandboxEvidence.AddHostEvidence(new Zone(SecurityZone.Intranet));
                } 
                else if (level == AddInSecurityLevel.FullTrust)
                {
                    sandboxEvidence.AddHostEvidence(new Zone(SecurityZone.MyComputer));
                } 
                else if (level != AddInSecurityLevel.Internet)
                { 
                    throw new ArgumentOutOfRangeException("level"); 
                }
 

                return SecurityManager.GetStandardSandbox(sandboxEvidence);
            }
        } 

        // Assert full trust because we are seeing a full-trust demand here when there is 
        // an AppDomainManager configured that has an internal constructor 
        [System.Security.SecurityCritical]
        [PermissionSet(SecurityAction.Assert, Unrestricted=true)] 
        private static AppDomain CreateDomain(AddInToken token, PermissionSet permissionSet, String appDomainName)
        {
            AppDomainSetup setup = new AppDomainSetup();
            setup.ApplicationBase = Path.GetDirectoryName(token._addin.Location); 
            setup.ConfigurationFile = token._addin.Location + ".config";
            Assembly sysAddIn = typeof(AddInActivator).Assembly; 
            // 
            AppDomain domain = AppDomain.CreateDomain(appDomainName,
                AppDomain.CurrentDomain.Evidence, setup, permissionSet, 
                CreateStrongName(sysAddIn));  // Grant full trust to System.AddIn.dll
            // Ensure we load System.AddIn.dll in this new AD.
            domain.Load(sysAddIn.FullName);
            return domain; 
        }
 
        [System.Security.SecuritySafeCritical] 
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2129:SecurityTransparentCodeShouldNotReferenceNonpublicSecurityCriticalCode", Justification = "This is a SecurityRules.Level1 assembly, in which this rule is being incorrectly applied")]
        private static T Activate(AddInToken token, PermissionSet permissionSet, String appDomainName) 
        {
            // Don't let them create an appdomain that elevates privileges
            permissionSet.Demand();
 
            AppDomain domain = null;
            try 
            { 
                domain = CreateDomain(token, permissionSet, appDomainName);
 
                AddInEnvironment environment = new AddInEnvironment(domain, true);
                AddInControllerImpl controller = new AddInControllerImpl(environment, true, token);
                return ActivateInAppDomain(token, domain, controller, true);
            } 
            catch
            { 
                // Don't leak the domain. 
                if (domain != null)
                { 
                    try {
                        Utils.UnloadAppDomain(domain);
                    }
                    catch (AppDomainUnloadedException){} 
                }
                throw; 
            } 
        }
 
        internal static T Activate(AddInToken token, AppDomain target)
        {
            if (token == null)
                throw new ArgumentNullException("token"); 
            if (target == null)
                throw new ArgumentNullException("target"); 
            System.Diagnostics.Contracts.Contract.EndContractBlock(); 

            AddInEnvironment environment = new AddInEnvironment(target); 
            AddInControllerImpl controller = new AddInControllerImpl(environment, false, token);
            return ActivateInAppDomain(token, target, controller, false);
        }
 
        internal static T Activate(AddInToken token, PermissionSet permissionSet)
        { 
            if (token == null) 
                throw new ArgumentNullException("token");
            if (permissionSet == null) 
                throw new ArgumentNullException("permissionSet");
            System.Diagnostics.Contracts.Contract.EndContractBlock();

            return Activate(token, permissionSet, token.Name); 
        }
 
        // OOP Activation 
        // 
        //  
        // 
        // 
        // 
        //  
        [System.Security.SecuritySafeCritical]
        internal static T Activate(AddInToken token, AddInProcess process, PermissionSet permissionSet) 
        { 
            if (token == null)
                throw new ArgumentNullException("token"); 
            if (permissionSet == null)
                throw new ArgumentNullException("permissionSet");
            if (process == null)
                throw new ArgumentNullException("process"); 
            System.Diagnostics.Contracts.Contract.EndContractBlock();
 
            // check that they have ExecutionPermission.  Otherwise OOP remoting fails 
            // by shutting down the pipe, leaving the user scratching his head.
            if (!permissionSet.IsUnrestricted()) 
            {
                SecurityPermission p = (SecurityPermission)permissionSet.GetPermission(typeof(SecurityPermission));
                SecurityPermissionFlag requiredFlags = SecurityPermissionFlag.Execution;
                if (p == null || (p.Flags & requiredFlags) != requiredFlags) 
                    throw new ArgumentException(Res.NeedSecurityFlags);
            } 
 
            RemotingHelper.InitializeClientChannel();
 
            AddInServer addInServer = process.GetAddInServer();

            AddInServerWorker addInServerWorker = addInServer.CreateDomain(token, permissionSet);
            AddInEnvironment fullEnvironment = new AddInEnvironment(process, addInServerWorker); 

            return ActivateOutOfProcess(token, fullEnvironment, true); 
        } 

        internal static T Activate(AddInToken token, AddInProcess process, AddInSecurityLevel level) 
        {
            PermissionSet permissionSet = GetPermissionSetForLevel(level);
            return Activate(token, process, permissionSet);
        } 

        // Activation in an existing appdomain, either in-process or out-of-process 
        internal static T Activate(AddInToken token, AddInEnvironment environment) 
        {
            if (environment == null) 
                throw new ArgumentNullException("environment");
            System.Diagnostics.Contracts.Contract.EndContractBlock();

            if (environment.Process.IsCurrentProcess) 
            {
                AddInControllerImpl controller = new AddInControllerImpl(environment, false, token); 
                return ActivateInAppDomain(token, environment.AppDomain, controller, false); 
            }
            else 
            {
                return ActivateOutOfProcess(token, environment, false);
            }
        } 

        // helper method 
        // 
        private static T ActivateOutOfProcess(AddInToken token, AddInEnvironment environment, bool weOwn)
        { 
            ActivationWorker worker;
            IContract contract = environment.AddInServerWorker.Activate(token, out worker);

            AddInControllerImpl controller = new AddInControllerImpl(environment, weOwn, token); 
            controller.ActivationWorker = worker;
 
            T hav = AdaptToHost(token, contract); 
            if (weOwn)
                environment.AddInServerWorker.SetAppDomainOwner(contract); 

            // Add this HAV and add-in controller to our list of currently
            // non-disposed add-ins.
            controller.AssociateWithHostAddinView(hav, contract); 
            return hav;
        } 
 

        // Create a worker class in the remote appdomain, create the add-in & 
        // add-in adapter in the remote appdomain, then create the host adapter
        // in this appdomain, passing in a transparent proxy to the user's contract
        // implementation (which is really an instance of the add-in adapter).
        // The host adapter is a subclass of the host add-in view, which is our 
        // return value (T).  Also, associate the host add-in view with the add-in
        // controller. 
        //  
        // 
        //  
        // 
        // 
        // 
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2103:ReviewImperativeSecurity", Justification = "Reviewed"), 
         System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "Reviewed"),
         System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2001:AvoidCallingProblematicMethods", MessageId = "System.Reflection.Assembly.LoadFrom", Justification = "LoadFrom was designed for addin loading")] 
        [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")]
        private static T ActivateInAppDomain(AddInToken pipeline, AppDomain domain, AddInControllerImpl controller, bool weOwn) 
        {
            ContractComponent contract = pipeline._contract;
            HostAdapter hostAdapter = pipeline._hostAdapter;
 
            bool usingHostAppDomain = domain == AppDomain.CurrentDomain;
 
            //begin direct connect code 
            if (AddInToken.EnableDirectConnect && !weOwn && usingHostAppDomain)
            { 
                Type havType = typeof(T);
                TypeInfo havTypeInfo = new TypeInfo(havType);

                if (pipeline._addinBase.CanDirectConnectTo(havTypeInfo)) 
                {
                    // Connect directly for best performance. 
                    // Assert permission to the specific Addin directory only. 
                    PermissionSet permissionSet = new PermissionSet(PermissionState.None);
                    permissionSet.AddPermission(new FileIOPermission(FileIOPermissionAccess.Read | FileIOPermissionAccess.PathDiscovery, 
                        Path.GetDirectoryName(pipeline._addin.Location)));
                    permissionSet.Assert();

                    Assembly addInAssembly = Assembly.LoadFrom(pipeline._addin.Location); 
                    //
                    Type addinType = addInAssembly.GetType(pipeline._addin.TypeInfo.FullName, true); 
                    Object addIn = addinType.GetConstructor(new Type[0]).Invoke(new Object[0]); 
                    System.Diagnostics.Contracts.Contract.Assert(addIn != null, "Bypass couldn't create the add-in");
 
                    // remember the addin directly as the HAV.  Set the contract to null.
                    controller.AssociateWithHostAddinView(addIn, null);

                    return (T)addIn; 
                }
            } 
            //end direct connect code 

            // Use Activator.CreateInstance instead of AppDomain.CreateInstanceAndUnwrap 
            // because Activator will do the appropriate security asserts in the
            // remote appdomain.
            Type t = typeof(ActivationWorker);
            Object[] args = new Object[] { pipeline }; 
            ObjectHandle objHandle = Activator.CreateInstance(domain, t.Assembly.FullName, t.FullName,
                false, BindingFlags.Instance | BindingFlags.NonPublic, null, 
                args, null, null); 
            ActivationWorker activationWorker = (ActivationWorker) objHandle.Unwrap();
            activationWorker.UsingHostAppDomain = usingHostAppDomain; 

            System.AddIn.Contract.IContract addInContract = null;
            try
            { 
                addInContract = activationWorker.Activate();
            } 
            catch (Exception ex) 
            {
                CheckForDuplicateAssemblyProblems(pipeline, ex); 
                throw;
            }

            if (weOwn) 
                domain.SetData(ContractHandle.s_appDomainOwner, addInContract);
 
            controller.ActivationWorker = activationWorker; 
            T hav = AdaptToHost(pipeline, addInContract);
            controller.AssociateWithHostAddinView(hav, addInContract); 

            return hav;
        }
 

        //  
        //  
        // 
        //  
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification="Reviewed")]
        [System.Security.SecuritySafeCritical]
        private static T AdaptToHost(AddInToken pipeline, IContract addInContract)
        { 
            if (addInContract == null)
                throw new ArgumentNullException("addInContract"); 
            System.Diagnostics.Contracts.Contract.EndContractBlock(); 

            ContractComponent contract = pipeline._contract; 
            HostAdapter hostAdapter = pipeline._hostAdapter;

            Type hostAdapterType;
            Type contractType; 
            LoadContractAndHostAdapter(contract, hostAdapter, out contractType, out hostAdapterType);
 
            int? temporaryToken = null; 
            try
            { 
                temporaryToken = addInContract.AcquireLifetimeToken();

                // This assembly resolve event exists to:
                //    1) To upgrade the contract assembly from the LoadFrom context to 
                //       the default loader context
                ResolverHelper resolver = new ResolverHelper(pipeline); 
                ResolveEventHandler assemblyResolver = new ResolveEventHandler(resolver.ResolveAssemblyForHostAdapter); 
                AppDomain.CurrentDomain.AssemblyResolve += assemblyResolver;
 
                // Create the Host Adapter, which is a subclass of the Host Add-In View.
                // Pass the contract implementation to this constructor, using a
                // transparent proxy to the real type.  Detect common errors here.
                InvokerDelegate myInvokerDelegate = CreateConsInvoker(hostAdapterType, contractType); 

                T hav; 
                try 
                {
                    hav = (T)myInvokerDelegate(addInContract); 
                }
                catch (ArgumentException e)
                {
                    CheckForLoaderContextProblems(contract, pipeline._addinAdapter, e); 
                    throw;
                } 
                finally 
                {
                    AppDomain.CurrentDomain.AssemblyResolve -= assemblyResolver; 
                }

                return hav;
            } 
            finally
            { 
                if (temporaryToken != null && addInContract != null) 
                    addInContract.RevokeLifetimeToken((int)temporaryToken);
            } 
        }

        // Delegate used to invoke the constructor of the adapter, providing a contract, and return
        // the adapter. 
        internal delegate Object InvokerDelegate(Object contract);
 
        //  
        // 
        //  
        /// This method is used instead of the usual reflection Invoke on the constructor because
        /// we need to Assert the ability to see the internal constructor, but we don't
        /// want that Assert to carry over into the user code inside the constructor.  Reflection.Emit(LWCG)
        /// allows us to "see" the internal members first and then invoke them later in a separate action. 
        [System.Security.SecuritySafeCritical]
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2129:SecurityTransparentCodeShouldNotReferenceNonpublicSecurityCriticalCode", Justification = "This is a SecurityRules.Level1 assembly, in which this rule is being incorrectly applied")] 
        internal static InvokerDelegate CreateConsInvoker(Type targetType, Type argType) 
        {
            ConstructorInfo havCtor = targetType.GetConstructor( 
                BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance,
                null, new Type[]{argType}, null);

            Type[] methodArgs = new Type[]{typeof(Object)}; 
            DynamicMethod invoker = AssertAndCreateInvoker(targetType, argType, methodArgs, havCtor);
 
            return (InvokerDelegate)invoker.CreateDelegate(typeof(InvokerDelegate)); 
        }
 

        /// We assert full trust because that is needed in scenarios where the caller is lower
        /// trust than the callee assembly.  The demand happens when the call is jitted, but
        /// the stack is captured when the DynamicMethod is created. 
        [PermissionSet(SecurityAction.Assert, Unrestricted=true)]
        [System.Security.SecurityCritical] 
        private static DynamicMethod AssertAndCreateInvoker(Type targetType, Type argType,  Type[] methodArgs, ConstructorInfo havCtor) 
        {
            // As a workaround to a red bits bug that leaks memory, we don't associate this 
            // DM with an assembly.  Instead, we host it anonymously, and we need to assert
            // full trust.
            DynamicMethod invoker = new DynamicMethod(targetType.Name + "_ConstructorInvoker", // name, only usefult for debugging
                                                      typeof(Object),  // return type 
                                                      methodArgs, // parameterTypes
                                                      true); // skip visibility 
            ILGenerator il = invoker.GetILGenerator(); 
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Castclass, argType); // need to cast Object to the specific Contract type expected by the constructor 
            il.Emit(OpCodes.Newobj, havCtor); // invoke the constructor
            il.Emit(OpCodes.Ret);

            return invoker; 
        }
 
        //  
        // 
        //  
        [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 static void LoadContractAndHostAdapter(ContractComponent contract, HostAdapter hostAdapter,
                out Type contractType, out Type hostAdapterType) 
        { 
            PermissionSet assertSet = new PermissionSet(PermissionState.None);
            assertSet.AddPermission(new FileIOPermission(FileIOPermissionAccess.Read | FileIOPermissionAccess.PathDiscovery, hostAdapter.Location)); 
            assertSet.AddPermission(new FileIOPermission(FileIOPermissionAccess.Read | FileIOPermissionAccess.PathDiscovery, contract.Location));
            assertSet.Assert();

            // Explicitly load the host adapter & contract first, using LoadFrom 
            // to ensure they are loaded in the same loader context.
            Assembly hostAdapterAssembly = Assembly.LoadFrom(hostAdapter.Location); 
            Assembly contractAssembly = Assembly.LoadFrom(contract.Location); 

            hostAdapterType = hostAdapterAssembly.GetType(hostAdapter.TypeInfo.FullName, true); 
            contractType = contractAssembly.GetType(contract.TypeInfo.FullName, true);
        }

        // This method is used to re-adapt a given addin to another HAV 
        // 
        //  
        //  
        // 
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification="Reviewed")] 
        [System.Security.SecuritySafeCritical]
        internal static T ActivateHostAdapter(PartialToken pipeline, IContract addIn)
        {
            if (pipeline == null) 
                throw new ArgumentNullException("pipeline");
            if (addIn == null) 
                throw new ArgumentNullException("addIn"); 
            System.Diagnostics.Contracts.Contract.EndContractBlock();
 
            ContractComponent contract = pipeline._contract;
            HostAdapter hostAdapter = pipeline._hostAdapter;

            Type hostAdapterType; 
            Type contractType;
            LoadContractAndHostAdapter(contract, hostAdapter, out contractType, out hostAdapterType); 
 
            // This assembly resolve event exists to:
            //    1) To upgrade the contract assembly from the LoadFrom context to 
            //       the default loader context
            ResolverHelper resolver = new ResolverHelper(contract);
            ResolveEventHandler assemblyResolver = new ResolveEventHandler(resolver.ResolveAssemblyForHostAdapter);
            AppDomain.CurrentDomain.AssemblyResolve += assemblyResolver; 

            T hav; 
 
            InvokerDelegate myInvokerDelegate = CreateConsInvoker(hostAdapterType, contractType);
            try 
            {
                hav = (T)myInvokerDelegate(addIn);
            }
            catch (ArgumentException e) 
            {
                CheckForLoaderContextProblems(contract, pipeline._addinAdapter, e); 
                throw; 
            }
            finally 
            {
                AppDomain.CurrentDomain.AssemblyResolve -= assemblyResolver;
            }
 
            return hav;
        } 
 

        private static void CheckForDuplicateAssemblyProblems(AddInToken pipeline, Exception inner) 
        {
            Collection warnings = new Collection();
            bool duplicates = pipeline.HasDuplicatedAssemblies(null, warnings);
            if (duplicates) 
            {
                String[] s = new String[warnings.Count]; 
                warnings.CopyTo(s, 0); 
                throw new InvalidOperationException(String.Join("\n", s), inner);
            } 
        }

        // Detects two somewhat easy to hit user bugs, where the contract assembly
        // is loaded twice in different loader contexts, or where the add-in adapter 
        // has been loaded in the host's assembly.  If either of these happens,
        // then the transparent proxy will not be castable to the interface type, 
        // and the remoting code will attempt to load the addin adapter's 
        // type in the host's appdomain.
        // We explicitly do not allow the add-in adapter's assembly to leak 
        // into this appdomain.  If the contract assembly exists in the same
        // directory as the application, or in potentially other locations, it may
        // get loaded twice in different loader contexts by the CLR V2's loader.
        // This took about a week to debug, with experts from all the affected areas. 
        private static void CheckForLoaderContextProblems(ContractComponent contract, AddInAdapter addinAdapter, Exception inner)
        { 
            String contractAsmName = contract.TypeInfo.AssemblyName; 
            String addinAdapterAsmName = addinAdapter.TypeInfo.AssemblyName;
 
            List contracts = new List();
            List addinAdapters = new List();
            foreach (Assembly a in AppDomain.CurrentDomain.GetAssemblies()) {
                String aName = a.GetName().FullName; 
                if (aName == contractAsmName)
                    contracts.Add(a); 
                if (aName == addinAdapterAsmName) 
                    addinAdapters.Add(a);
            } 

            if (addinAdapters.Count > 0) {
                StringBuilder locations = new StringBuilder();
                foreach (Assembly a in addinAdapters) { 
                    locations.Append(Environment.NewLine);
                    locations.Append(a.CodeBase); 
                } 

                Exception e = new InvalidOperationException( 
                    String.Format(CultureInfo.CurrentCulture, Res.AddInAdapterLoadedInWrongAppDomain,
                        addinAdapter.TypeInfo.AssemblyName, addinAdapter.Location, locations.ToString()), inner);
                e.Data["Incorrectly loaded add-in adapters"] = addinAdapters;
                e.Data["Expected adapter location"] = addinAdapter.Location; 
                if (contracts.Count > 1)
                    e.Data["Duplicate Contracts"] = contracts; 
                throw e; 
            }
 
            if (contracts.Count > 1) {
                StringBuilder locations = new StringBuilder();
                foreach (Assembly a in contracts)
                { 
                    locations.Append(Environment.NewLine);
                    locations.Append(a.CodeBase); 
                } 

                Exception e = new InvalidOperationException( 
                    String.Format(CultureInfo.CurrentCulture, Res.ContractAssemblyLoadedMultipleTimes,
                        contract.TypeInfo.AssemblyName, contract.Location, locations.ToString()), inner);
                e.Data["Incorrectly loaded contracts"] = contracts;
                e.Data["Expected contract location"] = contract.Location; 
                throw e;
            } 
            else { 
                // If you're seeing this in a debugger on V2 of the CLR, make sure you hook the assembly resolve event.
                // Otherwise, see if there was an ArgumentException thrown from an HAV's constructor. 
                System.Diagnostics.Contracts.Contract.Assert(false, "Did the AddIn Model upgrade the contract to the default loader context using an assembly resolve event?  Either that, or your HAV's constructor threw an ArgumentException");
            }
        }
 
        internal sealed class ResolverHelper
        { 
            private ContractComponent _contract; 

            internal ResolverHelper(AddInToken pipeline) : this(pipeline._contract) 
            {
            }

            internal ResolverHelper(ContractComponent contract) 
            {
                _contract = contract; 
            } 

            internal Assembly ResolveAssemblyForHostAdapter(Object sender, ResolveEventArgs args) 
            {
                System.Diagnostics.Contracts.Contract.Assert(_contract != null);

                String assemblyRef = args.Name; 
                //Console.WriteLine("ResolveAssemblyForHostAdapter: {0}", assemblyRef);
 
                // We load the contract assembly in the LoadFrom context, but we 
                // need it in the default loader context.  In the V2 loader, we'll
                // need to explicitly return the currently loaded contract assembly 
                // here, which will "upgrade" the assembly from LoadFrom to default.
                Assembly a = Utils.FindLoadedAssemblyRef(assemblyRef);
                if (a != null)
                    return a; 

                // look in the contracts folder, in case there is a second contract there 
                // this HostAdapter depends on. 
                List dirsToLookIn = new List();
                string contractsDir = Path.GetDirectoryName(_contract.Location); 
                dirsToLookIn.Add(contractsDir);

                return Utils.LoadAssemblyFrom(dirsToLookIn, assemblyRef);
            } 
        }
 
        ///  
        /// Create a StrongName that matches a specific assembly
        ///  
        /// 
        /// if  is null
        /// 
        ///  
        /// if  does not represent a strongly named assembly
        ///  
        /// Assembly to create a StrongName for 
        /// A StrongName that matches the given assembly
        //  
        // 
        // 
        [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 static StrongName CreateStrongName(Assembly assembly)
        { 
            System.Diagnostics.Contracts.Contract.Requires(assembly != null); 

            // Since there is no managed API for finding the GAC path, I 
            // assert path discovery for all local files.
            FileIOPermission permission = new FileIOPermission(PermissionState.None);
            permission.AllLocalFiles = FileIOPermissionAccess.PathDiscovery;
            permission.Assert(); 
            AssemblyName assemblyName = assembly.GetName();
            CodeAccessPermission.RevertAssert(); 
 
            // get the public key blob
            byte[] publicKey = assemblyName.GetPublicKey(); 
            if (publicKey == null || publicKey.Length == 0)
                throw new InvalidOperationException(Res.NoStrongName);

            StrongNamePublicKeyBlob keyBlob = new StrongNamePublicKeyBlob(publicKey); 

            // and create the StrongName 
            return new StrongName(keyBlob, assemblyName.Name, assemblyName.Version); 
        }
    } 
}

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