简体   繁体   English

如何使用EnvDTE列出当前解决方案中的所有项目?

[英]How do I list all the projects in the current solution using EnvDTE?

I've been following MSDN's Hello World guide to developing Visual Studio extensions (this article specifically deals with creating one as a Visual Studio toolbar command). 我一直在关注MSDN的Hello World指南来开发Visual Studio扩展 (本文专门讨论如何创建一个Visual Studio工具栏命令)。

I am trying to list all projects contained in the current/active solution. 我正在尝试列出当前/活动解决方案中包含的所有项目。

In the auto generated code for the Command template. 在Command模板的自动生成代码中。

I have tried EnvDTE 's Solution 's Projects property, but it shows zero projects. 我已经尝试过EnvDTESolutionProjects属性,但它显示零项目。

There is a ActiveSolutionProjects property as well, but it also shows an empty array. 还有一个ActiveSolutionProjects属性,但它也显示一个空数组。

How is this achieved ? 这是如何实现的?

PS: I tried both DTE and DTE2 interfaces since it is confusing understanding which version to use, from the docs. PS:我尝试了DTE和DTE2接口,因为从文档中理解使用哪个版本令人困惑。 I get a null service for DTE2, so I am going with DTE. 我得到DTE2的空服务,所以我要去DTE。

在此输入图像描述

My Solution Explorer looks like: My Solution Explorer看起来像:

在此输入图像描述


Update : Bert Huijben, from gitter/extendvs , suggested the following, found at the VSSDK Extensibility Samples - but this too does not work (returns 0 elements, both within the constructor and within the callback function): 更新 :来自gitter / extendvs的 Bert Huijben建议在VSSDK可扩展性示例中找到以下内容 - 但这也不起作用(返回0个元素,在构造函数内和回调函数内):

private Hashtable GetLoadedControllableProjectsEnum()
{
    Hashtable mapHierarchies = new Hashtable();

    IVsSolution sol = (IVsSolution)this.ServiceProvider.GetService(typeof(SVsSolution));
    Guid rguidEnumOnlyThisType = new Guid();
    IEnumHierarchies ppenum = null;
    ErrorHandler.ThrowOnFailure(sol.GetProjectEnum((uint)__VSENUMPROJFLAGS.EPF_LOADEDINSOLUTION, ref rguidEnumOnlyThisType, out ppenum));

    IVsHierarchy[] rgelt = new IVsHierarchy[1];
    uint pceltFetched = 0;
    while (ppenum.Next(1, rgelt, out pceltFetched) == VSConstants.S_OK &&
           pceltFetched == 1)
    {
        IVsSccProject2 sccProject2 = rgelt[0] as IVsSccProject2;
        if (sccProject2 != null)
        {
            mapHierarchies[rgelt[0]] = true;
        }
    }

    return mapHierarchies;
}

To get the EnvDTE.Project objects: 要获取EnvDTE.Project对象:

    static private void FindProjectsIn(EnvDTE.ProjectItem item, List<EnvDTE.Project> results)
    {
        if (item.Object is EnvDTE.Project)
        {
            var proj = (EnvDTE.Project)item.Object;
            if (new Guid(proj.Kind) != Utilities.ProjectTypeGuids.Folder)
            {
                results.Add((EnvDTE.Project)item.Object);
            }
            else
            {
                foreach (EnvDTE.ProjectItem innerItem in proj.ProjectItems)
                {
                    FindProjectsIn(innerItem, results);
                }
            }
        }
        if (item.ProjectItems != null)
        {
            foreach (EnvDTE.ProjectItem innerItem in item.ProjectItems)
            {
                FindProjectsIn(innerItem, results);
            }
        }
    }

    static private void FindProjectsIn(EnvDTE.UIHierarchyItem item, List<EnvDTE.Project> results)
    {
        if (item.Object is EnvDTE.Project)
        {
            var proj = (EnvDTE.Project)item.Object;
            if (new Guid(proj.Kind) != Utilities.ProjectTypeGuids.Folder)
            {
                results.Add((EnvDTE.Project)item.Object);
            }
            else
            {
                foreach (EnvDTE.ProjectItem innerItem in proj.ProjectItems)
                {
                    FindProjectsIn(innerItem, results);
                }
            }
        }
        foreach (EnvDTE.UIHierarchyItem innerItem in item.UIHierarchyItems)
        {
            FindProjectsIn(innerItem, results);
        }
    }

    static internal IEnumerable<EnvDTE.Project> GetEnvDTEProjectsInSolution()
    {
        List<EnvDTE.Project> ret = new List<EnvDTE.Project>();
        EnvDTE80.DTE2 dte = (EnvDTE80.DTE2)ServiceProvider.GlobalProvider.GetService(typeof(EnvDTE.DTE));
        EnvDTE.UIHierarchy hierarchy = dte.ToolWindows.SolutionExplorer;
        foreach (EnvDTE.UIHierarchyItem innerItem in hierarchy.UIHierarchyItems)
        {
            FindProjectsIn(innerItem, ret);
        }
        return ret;
    }

Notably recursion is necessary to dig into solution folders. 值得注意的是,递归对于挖掘解决方案文件夹是必要的。

If you just want the file paths you can do this w/o using DTE: 如果您只想要文件路径,可以使用DTE执行此操作:

    static internal string[] GetProjectFilesInSolution()
    {
        IVsSolution sol = ServiceProvider.GlobalProvider.GetService(typeof(SVsSolution)) as IVsSolution;
        uint numProjects;
        ErrorHandler.ThrowOnFailure(sol.GetProjectFilesInSolution((uint)__VSGETPROJFILESFLAGS.GPFF_SKIPUNLOADEDPROJECTS, 0, null, out numProjects));
        string[] projects = new string[numProjects];
        ErrorHandler.ThrowOnFailure(sol.GetProjectFilesInSolution((uint)__VSGETPROJFILESFLAGS.GPFF_SKIPUNLOADEDPROJECTS, numProjects, projects, out numProjects));
        //GetProjectFilesInSolution also returns solution folders, so we want to do some filtering
        //things that don't exist on disk certainly can't be project files
        return projects.Where(p => !string.IsNullOrEmpty(p) && System.IO.File.Exists(p)).ToArray();
    }

Works for me: 适合我:

Add a field in your package for dte. 在包中添加一个字段用于dte。 Get the DTE service. 获得DTE服务。 Reference the Solution. 参考解决方案。

using EnvDTE;
using EnvDTE80;

In your constructor: 在你的构造函数中:

dte = this.ServiceProvider.GetService(typeof(EnvDTE.DTE)) as EnvDTE80.DTE2;

In your command handler: 在命令处理程序中:

Integer count = ((EnvDTE.SolutionClass)dte.Solution).Projects.Count;

I get the correct count from this. 我从中得到了正确的数量。

Screenshot (requested) 截图(请求)

在此输入图像描述

Code

//------------------------------------------------------------------------------
// <copyright file="Command1.cs" company="Company">
//     Copyright (c) Company.  All rights reserved.
// </copyright>
//------------------------------------------------------------------------------

using System;
using System.ComponentModel.Design;
using System.Globalization;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
using EnvDTE;
using EnvDTE80;

namespace SolExpExt
{
    internal sealed class Command1
    {
        public const int CommandId = 0x0100;
        public static readonly Guid CommandSet = new Guid("beff5a1a-dff5-4f6a-95c8-fd7ea7411a7b");
        private DTE2 dte;
        private readonly Package package;
        private IVsSolution sol;
        private Command1(Package package)
        {
            if (package == null)
            {
                throw new ArgumentNullException("package");
            }

            this.package = package;

            OleMenuCommandService commandService = this.ServiceProvider.GetService(typeof(IMenuCommandService)) as OleMenuCommandService;
            if (commandService != null)
            {
                var menuCommandID = new CommandID(CommandSet, CommandId);
                var menuItem = new MenuCommand(this.MenuItemCallback, menuCommandID);
                commandService.AddCommand(menuItem);
            }

            dte = this.ServiceProvider.GetService(typeof(EnvDTE.DTE)) as EnvDTE80.DTE2;
        }

        public static Command1 Instance
        {
            get;
            private set;
        }

        private IServiceProvider ServiceProvider
        {
            get
            {
                return this.package;
            }
        }

        public static void Initialize(Package package)
        {
            Instance = new Command1(package);
        }

        private void MenuItemCallback(object sender, EventArgs e)
        {
            string message = $"There are {dte.Solution.Projects.Count} projects in this solution.";
            string title = "Command1";

            VsShellUtilities.ShowMessageBox(
                this.ServiceProvider,
                message,
                title,
                OLEMSGICON.OLEMSGICON_INFO,
                OLEMSGBUTTON.OLEMSGBUTTON_OK,
                OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST);
        }
    }
}

Unfortunately could not find any working solution here, decided to post my own solution: 不幸的是在这里找不到任何可行的解决方案,决定发布我自己的解决方案

/// <summary>
/// Queries for all projects in solution, recursively (without recursion)
/// </summary>
/// <param name="sln">Solution</param>
/// <returns>List of projects</returns>
static List<Project> GetProjects(Solution sln)
{
    List<Project> list = new List<Project>();
    list.AddRange(sln.Projects.Cast<Project>());

    for (int i = 0; i < list.Count; i++)
        // OfType will ignore null's.
        list.AddRange(list[i].ProjectItems.Cast<ProjectItem>().Select(x => x.SubProject).OfType<Project>());

    return list;
}

And if you don't know what references / namespaces to add, you can pick up project with source code from here: 如果你不知道要添加什么引用/命名空间,你可以从这里获取包含源代码的项目:

https://github.com/tapika/cppscriptcore/blob/2a73f45474c8b2179774fd4715b8d8e80080f3ae/Tools/vsStart/Program.cs#L478 https://github.com/tapika/cppscriptcore/blob/2a73f45474c8b2179774fd4715b8d8e80080f3ae/Tools/vsStart/Program.cs#L478

And check namespaces / references. 并检查命名空间/引用。

The following, shamelessly taken from AutoFindReplace , works using VS2015 Community: 以下,从AutoFindReplace无耻地采取,使用VS2015社区:

using EnvDTE;
.
.
protected override void Initialize()
{
    base.Initialize();

    IServiceContainer serviceContainer = this as IServiceContainer;
    dte = serviceContainer.GetService(typeof(SDTE)) as DTE;
    var solutionEvents = dte.Events.SolutionEvents;
    solutionEvents.Opened += OnSolutionOpened;

    var i = dte.Solution.Projects.Count; // Happy days !
}

All the code lines above pre-exist in the solution within VSPackage.cs except for "var i = dte.Solution.Projects.Count;" 除了“var i = dte.Solution.Projects.Count;”之外, VSPackage.cs中的解决方案中预先存在上述所有代码行。 which I added locally to VSPackage.cs just after line 44 . 我在第44行之后本地添加到VSPackage.cs I then open the solution , hit F5, and within the Experimental Instance I opened JoePublic.Sln and hey presto the count was '2' correctly - Bingo ! 然后我打开解决方案 ,点击F5,在实验实例中,我打开了JoePublic.Sln ,嘿presto计数'2'正确 - 宾果! Happy days ! 快乐的时光 !

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何以编程方式列出解决方案中的所有项目? - How do I programmatically list all projects in a solution? 如何根据给定的NuGet包列出当前解决方案中的所有项目? - How can I list all projects in the current solution dependent on a given NuGet package? 在项目列表中使用lambda表达式[ENVDTE] - Using lambda expression in List of Projects [ENVDTE] 如何从解决方案中的所有项目中卸载* a *软件包 - How do I uninstall *a* package from all projects in solution C#EnvDTE将项目从Solution移动到SolutionFolder - C # EnvDTE Moving projects from the Solution to SolutionFolder 如何获取当前Visual Studio解决方案中的项目列表? - How to get list of projects in current Visual studio solution? 如何从VS 2017中的设置中获取当前的Projects&Solutions目录,并使用SDK加载解决方案? - How can I get the current Projects & Solutions directory from the settings in VS 2017 and load solution using SDK? 我可以在Visual Studio解决方案中列出所有*不可用*项目吗? - Can I list all *unavailable* projects in a Visual studio solution? 如何自动将解决方案中的所有项目设置为相同版本? - How do I automatically set all projects in my solution to the same version? 项目如何在解决方案中进行交互 - How do Projects interact in a Solution
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM