Code:
/ 4.0 / 4.0 / 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. // ==++== // // 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
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- XsdBuilder.cs
- HotSpotCollectionEditor.cs
- XmlDictionaryWriter.cs
- ActivationArguments.cs
- InstanceCreationEditor.cs
- Literal.cs
- SymbolMethod.cs
- SqlClientPermission.cs
- SizeF.cs
- TemplateControlCodeDomTreeGenerator.cs
- ScopelessEnumAttribute.cs
- BrowserCapabilitiesFactoryBase.cs
- ConfigurationSectionGroup.cs
- ListViewItemMouseHoverEvent.cs
- BasePattern.cs
- CodeMemberEvent.cs
- GridProviderWrapper.cs
- ProjectionPlan.cs
- DictionaryBase.cs
- ObjectDataSourceStatusEventArgs.cs
- ConnectionManagementElementCollection.cs
- DataGridViewDataConnection.cs
- ProgressBarHighlightConverter.cs
- DiagnosticTrace.cs
- GroupBoxRenderer.cs
- ConstraintStruct.cs
- _HTTPDateParse.cs
- VScrollProperties.cs
- PageContentAsyncResult.cs
- HtmlControl.cs
- SimpleExpression.cs
- FocusManager.cs
- LinqTreeNodeEvaluator.cs
- Timer.cs
- ApplicationId.cs
- WindowsIdentity.cs
- SQLDateTimeStorage.cs
- CompilerGeneratedAttribute.cs
- ValueOfAction.cs
- MenuItem.cs
- SpecialTypeDataContract.cs
- Decoder.cs
- XmlEntity.cs
- SimpleType.cs
- XappLauncher.cs
- TextRangeBase.cs
- EventEntry.cs
- TextServicesDisplayAttributePropertyRanges.cs
- ServiceChannelProxy.cs
- SubordinateTransaction.cs
- DataContext.cs
- PathTooLongException.cs
- DataGridColumnsPage.cs
- Label.cs
- IdentityValidationException.cs
- ToolTipService.cs
- EventHandlerList.cs
- ListBindingHelper.cs
- TableDetailsCollection.cs
- ResponseBodyWriter.cs
- FixedLineResult.cs
- DataAdapter.cs
- Conditional.cs
- InputLanguage.cs
- CompilerTypeWithParams.cs
- XmlAttributeProperties.cs
- ActivationServices.cs
- SafeReadContext.cs
- AttachedAnnotation.cs
- BorderGapMaskConverter.cs
- HttpCapabilitiesSectionHandler.cs
- ConstrainedGroup.cs
- HttpListenerPrefixCollection.cs
- Container.cs
- OutputCacheProfileCollection.cs
- SuppressMergeCheckAttribute.cs
- NotifyParentPropertyAttribute.cs
- ServicePointManager.cs
- DialogResultConverter.cs
- LocalizableAttribute.cs
- DiscoveryReferences.cs
- RuntimeIdentifierPropertyAttribute.cs
- UserControlDocumentDesigner.cs
- BigInt.cs
- ColorContextHelper.cs
- MarkupCompilePass1.cs
- ActivationArguments.cs
- SyntaxCheck.cs
- RawStylusInput.cs
- Action.cs
- RotateTransform3D.cs
- IPGlobalProperties.cs
- ConfigurationException.cs
- Style.cs
- RegexCharClass.cs
- EntryPointNotFoundException.cs
- InputProcessorProfilesLoader.cs
- SecurityUtils.cs
- SqlFacetAttribute.cs
- BrowserCapabilitiesCodeGenerator.cs