| File: ExtensionFramework\VSExtensionManager.cs | Web Access |
| Project: src\vstest\src\Microsoft.TestPlatform.Common\Microsoft.TestPlatform.Common.csproj (Microsoft.VisualStudio.TestPlatform.Common) |
// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; using System.Collections.Generic; using System.Globalization; using System.Reflection; using Microsoft.VisualStudio.TestPlatform.Common.Interfaces; using Microsoft.VisualStudio.TestPlatform.Common.Utilities; using Microsoft.VisualStudio.TestPlatform.ObjectModel; using Microsoft.VisualStudio.TestPlatform.Utilities.Helpers; using Microsoft.VisualStudio.TestPlatform.Utilities.Helpers.Interfaces; namespace Microsoft.VisualStudio.TestPlatform.Common.ExtensionFramework; /// <summary> /// Manager for VisualStudio based extensions /// </summary> public class VSExtensionManager : IVSExtensionManager { private const string ExtensionManagerService = "Microsoft.VisualStudio.ExtensionManager.ExtensionManagerService"; private const string ExtensionManagerAssemblyName = @"Microsoft.VisualStudio.ExtensionManager"; private const string ExtensionManagerImplAssemblyName = @"Microsoft.VisualStudio.ExtensionManager.Implementation"; private const string SettingsManagerTypeName = "Microsoft.VisualStudio.Settings.ExternalSettingsManager"; private const string SettingsManagerAssemblyName = @"Microsoft.VisualStudio.Settings.15.0"; private readonly IFileHelper _fileHelper; private Assembly? _extensionManagerAssembly; private Assembly? _extensionManagerImplAssembly; private Type? _extensionManagerServiceType; private Assembly? _settingsManagerAssembly; private Type? _settingsManagerType; /// <summary> /// Default constructor for manager for Visual Studio based extensions /// </summary> public VSExtensionManager() : this(new FileHelper()) { } internal VSExtensionManager(IFileHelper fileHelper) { _fileHelper = fileHelper; } /// <summary> /// Get the available unit test extensions installed. /// If no extensions are installed then it returns an empty list. /// </summary> /// <returns></returns> public IEnumerable<string> GetUnitTestExtensions() { try { return GetTestExtensionsInternal(Constants.UnitTestExtensionType); } catch (Exception ex) { string message = string.Format(CultureInfo.CurrentCulture, Resources.Resources.FailedToFindInstalledUnitTestExtensions, ex); throw new TestPlatformException(message, ex); } } /// <summary> /// Get the unit tests extensions /// </summary> private IEnumerable<string> GetTestExtensionsInternal(string extensionType) { IEnumerable<string>? installedExtensions = new List<string>(); // Navigate up to the IDE folder // In case of xcopyable vstest.console, this functionality is not supported. var installContext = new InstallationContext(_fileHelper); if (!installContext.TryGetVisualStudioDirectory(out string vsInstallPath)) { throw new TestPlatformException(string.Format(CultureInfo.CurrentCulture, Resources.Resources.VSInstallationNotFound)); } // Adding resolution paths for resolving dependencies. var resolutionPaths = installContext.GetVisualStudioCommonLocations(vsInstallPath); using (var assemblyResolver = new AssemblyResolver(resolutionPaths)) { var settingsManager = SettingsManagerType.GetMethod("CreateForApplication", [typeof(string)])?.Invoke(null, [installContext.GetVisualStudioPath(vsInstallPath)]); if (settingsManager == null) { EqtTrace.Warning("VSExtensionManager : Unable to create settings manager"); return installedExtensions; } try { // create extension manager var extensionManager = Activator.CreateInstance(ExtensionManagerServiceType, settingsManager); if (extensionManager != null) { installedExtensions = ExtensionManagerServiceType.GetMethod("GetEnabledExtensionContentLocations", [typeof(string)])?.Invoke( extensionManager, [extensionType]) as IEnumerable<string>; } else { EqtTrace.Warning("VSExtensionManager : Unable to create extension manager"); } } finally { // Dispose the settings manager if (settingsManager is IDisposable disposable) { disposable.Dispose(); } } } return installedExtensions ?? new List<string>(); } /// <summary> /// Used to explicitly load Microsoft.VisualStudio.ExtensionManager.dll /// </summary> private Assembly ExtensionManagerDefAssembly { get { _extensionManagerAssembly ??= Assembly.Load(new AssemblyName(ExtensionManagerAssemblyName)); return _extensionManagerAssembly; } } /// <summary> /// Used to explicitly load Microsoft.VisualStudio.ExtensionManager.Implementation.dll /// </summary> private Assembly? ExtensionManagerImplAssembly { get { if (_extensionManagerImplAssembly == null) { // Make sure ExtensionManager assembly is already loaded. Assembly extensionMgrAssembly = ExtensionManagerDefAssembly; if (extensionMgrAssembly != null) { _extensionManagerImplAssembly = Assembly.Load(new AssemblyName(ExtensionManagerImplAssemblyName)); } } return _extensionManagerImplAssembly; } } /// <summary> /// Returns the Type of ExtensionManagerService. /// </summary> private Type ExtensionManagerServiceType { get { if (_extensionManagerServiceType == null) { TPDebug.Assert(ExtensionManagerImplAssembly is not null, "ExtensionManagerImplAssembly is null"); _extensionManagerServiceType = ExtensionManagerImplAssembly.GetType(ExtensionManagerService); TPDebug.Assert(_extensionManagerServiceType is not null, "_extensionManagerServiceType is null"); } return _extensionManagerServiceType; } } /// <summary> /// Used to explicitly load Microsoft.VisualStudio.Settings.15.0.dll /// </summary> private Assembly SettingsManagerAssembly { get { _settingsManagerAssembly ??= Assembly.Load(new AssemblyName(SettingsManagerAssemblyName)); return _settingsManagerAssembly; } } private Type SettingsManagerType { get { if (_settingsManagerType == null) { _settingsManagerType = SettingsManagerAssembly.GetType(SettingsManagerTypeName); TPDebug.Assert(_settingsManagerType is not null, "_settingsManagerType is null"); } return _settingsManagerType; } } }