/// <summary> /// Adds references to one or more assembly files. /// </summary> public async Task AddAsync(params string[] assemblyFileNames) { // Note: This method does not need to be async, but it's written // this way to be consistent with the other `AddAsync` methods. await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); IVsReferenceManagerUser manager = GetManager(); IVsReferenceProviderContext context; // Which provider context we need to use will depend on the type // of project style. Classic projects use assembly references, // and SDK-style projects use file references. if (TryGetProviderContext(manager, out IVsFileReferenceProviderContext fileContext)) { context = fileContext; } else if (TryGetProviderContext(manager, out IVsAssemblyReferenceProviderContext assemblyContext)) { context = assemblyContext; } else { throw new NotSupportedException($"The project '{_project.Name}' cannot have assembly references."); } foreach (string fileName in assemblyFileNames) { IVsReference reference = context.CreateReference(); reference.Name = Path.GetFileNameWithoutExtension(fileName); reference.FullPath = fileName; context.AddReference(reference); } manager.ChangeReferences((uint)__VSREFERENCECHANGEOPERATION.VSREFERENCECHANGEOPERATION_ADD, context); }
private T GetProviderContext <T>(IVsReferenceManagerUser manager) where T : IVsReferenceProviderContext { ThreadHelper.ThrowIfNotOnUIThread(); if (!TryGetProviderContext <T>(manager, out T context)) { throw new NotSupportedException($"Could not find the {typeof(T).Name} for the project."); } return(context); }
private bool TryGetProviderContext <T>(IVsReferenceManagerUser manager, out T context) where T : IVsReferenceProviderContext { ThreadHelper.ThrowIfNotOnUIThread(); T?value = manager.GetProviderContexts().OfType <T>().FirstOrDefault(); if (value is not null) { context = value; return(true); } context = default !;
/// <summary> /// Adds references to one or more projects. /// </summary> public async Task AddAsync(params Project[] projects) { await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); IVsSolution solution = await VS.Services.GetSolutionAsync(); IVsReferenceManagerUser manager = GetManager(); Lazy <IVsProjectReferenceProviderContext> projectContext = new(() => GetProviderContext <IVsProjectReferenceProviderContext>(manager), false); Lazy <IVsSharedProjectReferenceProviderContext> sharedContext = new(() => GetProviderContext <IVsSharedProjectReferenceProviderContext>(manager), false); foreach (Project project in projects) { project.GetItemInfo(out IVsHierarchy hierarchy, out uint itemId, out _); IVsSharedAssetsProject?sharedProject = hierarchy.GetSharedAssetsProject(); if (sharedProject is not null) { IVsSharedProjectReference reference = (IVsSharedProjectReference)sharedContext.Value.CreateReference(); PopulateSharedProjectReference(reference, solution, project, sharedProject); sharedContext.Value.AddReference(reference); } else { ErrorHandler.ThrowOnFailure(solution.GetUniqueNameOfProject(hierarchy, out string uniqueName)); ErrorHandler.ThrowOnFailure(solution.GetGuidOfProject(hierarchy, out Guid projectGuid)); IVsProjectReference reference = (IVsProjectReference)projectContext.Value.CreateReference(); reference.Name = project.Name; reference.FullPath = project.FullPath; reference.Identity = projectGuid.ToString("b"); // The reference specification is made up of the project’s GUID and the // project's Visual Studio unique name, separated by a "|" character. reference.ReferenceSpecification = $"{projectGuid:b}|{uniqueName}"; projectContext.Value.AddReference(reference); } } if (projectContext.IsValueCreated) { manager.ChangeReferences((uint)__VSREFERENCECHANGEOPERATION.VSREFERENCECHANGEOPERATION_ADD, projectContext.Value); } if (sharedContext.IsValueCreated) { manager.ChangeReferences((uint)__VSREFERENCECHANGEOPERATION.VSREFERENCECHANGEOPERATION_ADD, sharedContext.Value); } }
private bool TryGetManager(out IVsReferenceManagerUser manager) { _project.GetItemInfo(out IVsHierarchy hierarchy, out uint itemId, out _); IVsReferenceManagerUser?value = HierarchyUtilities.GetHierarchyProperty <IVsReferenceManagerUser?>( hierarchy, itemId, (int)__VSHPROPID5.VSHPROPID_ReferenceManagerUser ); if (value is not null) { manager = value; return(true); } manager = null !; return(false); }
/// <summary> /// Removes the given references from the project. /// </summary> /// <param name="references">The references to remove.</param> /// <returns>A task.</returns> public async Task RemoveAsync(params Reference[] references) { await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); // There doesn't seem to be an easy way to actually remove references from a project. // There is no direct way to map an `IVsReference` instance to the provider that handles // that type of reference, and the `IVsReferenceProviderContext` has no way to remove a // reference from its `References` property. What we do here might seem like a bit of a hack, // but it appears to work fine. // // We start by creating a mapping from an `IVsReference` type to the corresponding provider // context by getting each provider context to create a reference object. The provider // context just creates a new object and doesn't seem to do anything with it, so this // shouldn't have any side effects. This gives us a way to get the provider context // that an `IVsReference` object is handled by. // // But, the provider contexts from the manager contain all of the existing references with no // way to remove reference objects from them, so we can't pass those contexts to the manager // when calling `ChangeReferences()` because that will remove all existing references! // What we will do is create an instance of our own implementation of a provider context // so that the provider context will only contain the references that we want to remove. Dictionary <Type, RemovingReferenceProviderContext> contextsByReferenceType = new(); IVsReferenceManagerUser manager = GetManager(); foreach (IVsReferenceProviderContext context in manager.GetProviderContexts().OfType <IVsReferenceProviderContext>()) { contextsByReferenceType[context.CreateReference().GetType()] = new RemovingReferenceProviderContext(context.ProviderGuid); } foreach (Reference reference in references) { if (contextsByReferenceType.TryGetValue(reference.VsReference.GetType(), out RemovingReferenceProviderContext context)) { context.AddReference(reference.VsReference); } } foreach (IVsReferenceProviderContext context in contextsByReferenceType.Values.Where((x) => x.HasReferences)) { manager.ChangeReferences((uint)__VSREFERENCECHANGEOPERATION.VSREFERENCECHANGEOPERATION_REMOVE, context); } }