How to get all projects name in a solution?
Check this MSDN that will resolve your query.
The .sln file contains text-based information the environment uses to
find and load the name-value parameters for the persisted data and the
project VSPackages it references. When a user opens a solution, the
environment cycles through the preSolution, Project, and postSolution
information in the .sln file to load the solution, projects within the
solution, and any persisted information attached to the solution.
Also check EnvDTE : Getting all projects .
Also check this Thread(Full credit to John Leidegren for providing such a nice answer)
public class Solution
{
//internal class SolutionParser
//Name: Microsoft.Build.Construction.SolutionParser
//Assembly: Microsoft.Build, Version=4.0.0.0
static readonly Type s_SolutionParser;
static readonly PropertyInfo s_SolutionParser_solutionReader;
static readonly MethodInfo s_SolutionParser_parseSolution;
static readonly PropertyInfo s_SolutionParser_projects;
static Solution()
{
s_SolutionParser = Type.GetType("Microsoft.Build.Construction.SolutionParser, Microsoft.Build, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", false, false);
if (s_SolutionParser != null)
{
s_SolutionParser_solutionReader = s_SolutionParser.GetProperty("SolutionReader", BindingFlags.NonPublic | BindingFlags.Instance);
s_SolutionParser_projects = s_SolutionParser.GetProperty("Projects", BindingFlags.NonPublic | BindingFlags.Instance);
s_SolutionParser_parseSolution = s_SolutionParser.GetMethod("ParseSolution", BindingFlags.NonPublic | BindingFlags.Instance);
}
}
public List<SolutionProject> Projects { get; private set; }
public Solution(string solutionFileName)
{
if (s_SolutionParser == null)
{
throw new InvalidOperationException("Can not find type 'Microsoft.Build.Construction.SolutionParser' are you missing a assembly reference to 'Microsoft.Build.dll'?");
}
var solutionParser = s_SolutionParser.GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic).First().Invoke(null);
using (var streamReader = new StreamReader(solutionFileName))
{
s_SolutionParser_solutionReader.SetValue(solutionParser, streamReader, null);
s_SolutionParser_parseSolution.Invoke(solutionParser, null);
}
var projects = new List<SolutionProject>();
var array = (Array)s_SolutionParser_projects.GetValue(solutionParser, null);
for (int i = 0; i < array.Length; i++)
{
projects.Add(new SolutionProject(array.GetValue(i)));
}
this.Projects = projects;
}
}
[DebuggerDisplay("{ProjectName}, {RelativePath}, {ProjectGuid}")]
public class SolutionProject
{
static readonly Type s_ProjectInSolution;
static readonly PropertyInfo s_ProjectInSolution_ProjectName;
static readonly PropertyInfo s_ProjectInSolution_RelativePath;
static readonly PropertyInfo s_ProjectInSolution_ProjectGuid;
static SolutionProject()
{
s_ProjectInSolution = Type.GetType("Microsoft.Build.Construction.ProjectInSolution, Microsoft.Build, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", false, false);
if (s_ProjectInSolution != null)
{
s_ProjectInSolution_ProjectName = s_ProjectInSolution.GetProperty("ProjectName", BindingFlags.NonPublic | BindingFlags.Instance);
s_ProjectInSolution_RelativePath = s_ProjectInSolution.GetProperty("RelativePath", BindingFlags.NonPublic | BindingFlags.Instance);
s_ProjectInSolution_ProjectGuid = s_ProjectInSolution.GetProperty("ProjectGuid", BindingFlags.NonPublic | BindingFlags.Instance);
}
}
public string ProjectName { get; private set; }
public string RelativePath { get; private set; }
public string ProjectGuid { get; private set; }
public SolutionProject(object solutionProject)
{
this.ProjectName = s_ProjectInSolution_ProjectName.GetValue(solutionProject, null) as string;
this.RelativePath = s_ProjectInSolution_RelativePath.GetValue(solutionProject, null) as string;
this.ProjectGuid = s_ProjectInSolution_ProjectGuid.GetValue(solutionProject, null) as string;
}
}
How to iterate programmatically through all projects of Visual Studio 2008 solution considering Solution Folders
To work with VS2008 solutions, you need first of all
c:\Program Files (x86)\Microsoft Visual Studio 9.0\Common7\IDE\PublicAssemblies\EnvDTE.dll
but it does not expose all properties of all kinds of projects (e.g. the property "InheritedPropertySheets" in C++ projects is not accessible). To access C++ projects properly you will also need:
c:\Program Files (x86)\Microsoft Visual Studio 9.0\Common7\IDE\PublicAssemblies\Microsoft.VisualStudio.VCProjectEngine.dll
Example in C# (.NET 3.5) which traverses a solution, making sure each C++ project inherits our custom Property Sheet and then in the Post-Build Step uses the macro "THETARGETDIR" which is defined centrally in our Property Sheet.
using System;
using System.Runtime.InteropServices;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using EnvDTE;
using Microsoft.VisualStudio.VCProjectEngine;
namespace FixSolution
{
class Program
{
private class Stats
{
public int n_pbs_adjusted = 0;
public int n_projects = 0;
public int n_projects_cpp = 0;
public int n_ps_adjusted = 0;
public int n_consistency_errors = 0;
}
private static Stats _stats = new Stats();
static void ProcessSolutionFolder(Project p)
{
foreach (ProjectItem pi in p.ProjectItems)
{
Project pp = pi.Object as Project;
if (pp == null)
{
continue; // solution item but not a project (e.g. big_solution_explained.txt)
}
if (pp.Kind == FixSolution.Properties.Settings.Default.SF_GUID)
ProcessSolutionFolder(pp);
else
ProcessProject(pp);
}
}
private static int NextHardcoded(string cmd)
{
return cmd.ToLower().IndexOf(FixSolution.Properties.Settings.Default.STD_TARGET);
}
private static bool ProcessVCPostBuildEventTool(VCConfiguration c)
{
IVCCollection cc = c.Tools as IVCCollection;
if (cc == null) return false;
bool adjusted = false;
foreach (Object tool in cc)
{
VCPostBuildEventTool pbs = tool as VCPostBuildEventTool;
if (pbs == null || pbs.CommandLine == null) continue;
int pos = NextHardcoded(pbs.CommandLine);
var before_adjustment = pbs.CommandLine;
while (pos != -1)
{
adjusted = true;
string CMD = pbs.CommandLine;
int tl = FixSolution.Properties.Settings.Default.STD_TARGET.Length;
pbs.CommandLine = CMD.Substring(0, pos) + "$(THETARGETDIR)" + CMD.Substring(pos + tl, CMD.Length - pos - tl);
pos = NextHardcoded(pbs.CommandLine);
}
if (adjusted)
{
VCProject p = c.project as VCProject;
Console.WriteLine("\nWARNING: project " + p.ProjectFile
+ "\nConfiguration " + c.ConfigurationName + " contains hardcoded sophis directory in PBS:"
+ "\n" + before_adjustment);
Console.WriteLine("REPLACED BY:");
Console.WriteLine(pbs.CommandLine);
}
}
return adjusted;
}
private static void ProcessProject(Project pp)
{
++_stats.n_projects;
VCProject p = pp.Object as VCProject;
if (p == null)
return; // not a C++ project
++_stats.n_projects_cpp;
string vsprops_path = Util.GetRelativePath(p.ProjectDirectory, FixSolution.Properties.Settings.Default.AbsoluteVspropsPath);
bool adjusted_ps = false;
bool adjusted_pbs = false;
foreach (VCConfiguration c in (IVCCollection)p.Configurations)
{
if (ProcessVCPostBuildEventTool(c))
adjusted_pbs = true;
if (c.InheritedPropertySheets == vsprops_path)
{
continue;
}
if (c.InheritedPropertySheets.Length > 0)
{
Console.WriteLine("WARNING: project " + pp.FullName + " config " + c.Name + " has unusual InheritedPropertySheets: " + c.InheritedPropertySheets);
++_stats.n_consistency_errors; // counting the unexpected, per configuration
}
adjusted_ps = true;
c.InheritedPropertySheets = vsprops_path;
}
if (adjusted_ps)
++_stats.n_ps_adjusted;
if (adjusted_pbs)
++_stats.n_pbs_adjusted;
p.Save();
}
static DTE GetDTE(string solutionfile)
{
DTE dte = null;
try
{
dte = (DTE)System.Runtime.InteropServices.Marshal.GetActiveObject(
FixSolution.Properties.Settings.Default.ROT_PROG_ID);
}
catch (Exception)
{
Console.WriteLine("Could not get an instance of an already running Visual Studio. Trying to start a new one");
}
if (dte == null)
{
Type visualStudioType = Type.GetTypeFromProgID(
FixSolution.Properties.Settings.Default.ROT_PROG_ID);
dte = Activator.CreateInstance(visualStudioType) as DTE;
}
if (dte == null)
{
Console.WriteLine("Unable to get an instance of Visual Studio");
}
else
{
dte.MainWindow.Visible = true;
dte.Solution.Open(solutionfile);
}
return dte;
}
static void ProcessSolution(string solutionfile)
{
DTE dte = GetDTE(solutionfile);
foreach (Project pp in dte.Solution.Projects)
{
if (pp.Kind == FixSolution.Properties.Settings.Default.SF_GUID)
ProcessSolutionFolder(pp);
else
ProcessProject(pp);
}
Console.WriteLine(string.Format("\nn_projects={0}, n_projects_cpp={1}, n_pbs_adjusted={2}, n_ps_adjusted={3}; n_consistency_errors={4}",
_stats.n_projects, _stats.n_projects_cpp, _stats.n_pbs_adjusted, _stats.n_ps_adjusted, _stats.n_consistency_errors));
dte.Solution.Close();
}
static void Main(string[] args)
{
if (args.Length == 0)
{
Console.WriteLine(@"Usage: FixSolution c:\full\path\to\YourSolution.sln");
}
var solutionfile = args[0];
ProcessSolution(solutionfile);
}
}
}
App.config:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
<section name="FixSolution.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</sectionGroup>
</configSections>
<applicationSettings>
<FixSolution.Properties.Settings>
<setting name="AbsoluteVspropsPath" serializeAs="String">
<value>c:\svn\mainline\ourbuild.vsprops</value>
</setting>
<setting name="SF_GUID" serializeAs="String">
<value>{66A26720-8FB5-11D2-AA7E-00C04F688DDE}</value>
</setting>
<setting name="STD_TARGET" serializeAs="String">
<value>c:\apps\ourapp</value>
</setting>
<setting name="ROT_PROG_ID" serializeAs="String">
<value>VisualStudio.DTE.9.0</value>
</setting>
</FixSolution.Properties.Settings>
</applicationSettings>
</configuration>
ourbuild.vsprops
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioPropertySheet
ProjectType="Visual C++"
Version="8.00"
Name="build"
>
<UserMacro
Name="THETARGETDIR"
Value="c:\apps\ourapp"
PerformEnvironmentSet="true"
/>
</VisualStudioPropertySheet>
How to programmatically add/remove exsting projects to a solution?
I had the same problem...
Project.Remove() throws UnImplemented exception
the answer is to use:
Solution::Remove(Project prj);
and
Solution::AddFromTemplate( string FileName, string Destination, string ProjectName, bool Exclusive)
Visual Studio DTE - how to programmatically select multiple projects
To select multiple projects, for the first project call:
item.Select(vsUISelectionType.vsUISelectionTypeSelect);
for subsequent projects call:
if (!item.IsSelected)
item.Select(vsUISelectionType.vsUISelectionTypeToggle);
Get all nuget packages in solution
This is the final solution (along with unit test). The key is to use the Directory
library to iterate over all the projects in the solution and then use NuGet.Core
to analyze the NuGet packages in each project.
using Microsoft.VisualStudio.TestTools.UnitTesting;
using NuGet;
using Shouldly;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace UnitTests
{
[TestClass]
public class NugetConsolidationTest
{
private List<string> _ignoredPackages = new List<string>();
[TestMethod]
public void AllNugetPackagesAreConsolidated()
{
var packageVersionMapping = new Dictionary<string, List<string>>();
var parentDir = (Directory.GetParent(Directory.GetCurrentDirectory()).Parent).Parent.FullName;
var files = Directory.GetFiles(parentDir, "packages.config", SearchOption.AllDirectories);
foreach (var packageFile in files)
{
var file = new PackageReferenceFile(packageFile);
var refs = file.GetPackageReferences(true);
foreach (var packageRef in refs)
{
if (_ignoredPackages.Contains(packageRef.Id))
continue;
if (!packageVersionMapping.ContainsKey(packageRef.Id))
packageVersionMapping[packageRef.Id] = new List<string>() { packageRef.Version.ToFullString() };
else
{
if (packageVersionMapping[packageRef.Id].All(x => !x.Equals(packageRef.Version.ToFullString(),
StringComparison.InvariantCultureIgnoreCase)))
packageVersionMapping[packageRef.Id].Add(packageRef.Version.ToFullString());
}
}
}
var errors = packageVersionMapping.Where(x => x.Value.Count > 1)?.
Select(x => $"Package {x.Key} has {x.Value.Count} separate versions installed! Current versions are {string.Join(", ", x.Value)}");
errors.ShouldBeEmpty();
}
}
}
Get a list of files in a Solution/Project using DXCore console application
The original (and updated) post is located here.
Actually, DXCore is not designed to be used outside of Visual Studio, but there are always workarounds... In this article I'm going to show you how to use the DXCore Framework inside the regular C# Console Application to parse an entire solution and work with the abstract parsed tree. The solution should be passed-in as an argument to the program as a full complete path to the *.sln file. If there's no argument used, the hard-coded path to the test program is used, so the program will parse itself and print information about the solution, such as a list of all types used and the number of members inside of each class.
Let's create a new C# Console Application, call it TestDXCoreConsoleApp and save it inside the "C:\Project" folder:
Then, we should change the Target Framework version of the new project to Framework 4.0, so it's not a "Target Framework 4.0 Client Profile", because some required assembly references don't support this version of the Target Framework:
Now, let add required assembly references. Here's the list of what we need:
- DXCore assemblies:
- DevExpress.CodeRush.Common
- DevExpress.CodeRush.Core
- DevExpress.CodeRush.StructuralParser
- DevExpress.CodeRush.VSCore
- DevExpress.DXCore.AssemblyResolver
- DevExpress.DXCore.Parser
These assemblies canbe found inside your DevExpress IDE Tools installation folder. For example, the path may look like this:
C:\Program Files\DevExpress 2011.1\IDETools\System\DXCore\BIN
- Now, three additional assemblies for different program language support:
- DX_CPPLanguage
- DX_CSharpLanguage
- DX_VBLanguage
With these assemblies we are able to parse CSharp, Visual Basic and C++ projects. They can be found here:
C:\Program Files (x86)\DevExpress 2011.1\IDETools\System\DXCore\BIN\SYSTEM
- .NET Framework assemblies:
- Microsoft.Build.BuildEngine.dll
- And, finally, a couple of Visual Studio assemblies:
- EnvDTE
- VsLangProj
These two can be found in the "PublicAssemblies" folder:
C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\PublicAssemblies\
Now, the DXCore support code. This code is required to load a solution, its projects and initialize DXCore parsers. I've added two folders:
- The Helpers folder contains the following classes:
- LanguageHelper.cs - detects the language of projects (e.g. CSharp, Visual Basic or C++).
- ParserHelper.cs - initializes DXCore parsers, and a few important DXCore services - the Source Model service and the Language service which are used to parse source code.
- SolutionParser.cs - a helper class, which takes the path to the solution that you are going to parse. Calling the GetParsedSolution method will return the SolutionElement, which holds the abstract source tree of the entire solution.
- The Loaders folder contains the Visual Studio project and solution loaders for different Visual Studio versions. They are used to parse *.XXproj and *.sln files. There are versions for VS2002, VS2003 and VS2005. There are no dedicated loaders for VS2008 and VS2010, because those loaders for the old VS versions are perfectly fine to reading and loading newer Visual Studio project and solution format files (e.g. 2008, 2010).
Here's the final structure of the TestDXCoreConsoleApp:
The TestDXCoreConsoleApp with the full source is here (267,457 bytes, C#, VS2010), so you may review the code and use it as you'd like. Here's the Main function of the Program class:
static void Main(string[] args)
{
string SolutionPath;
if (args != null && args.Length > 0)
SolutionPath = args[0];
else
SolutionPath = @"c:\Projects\TestDXCoreConsoleApp\TestDXCoreConsoleApp.sln";
try
{
ParserHelper.RegisterParserServices();
Console.Write("Parsing solution... ");
SolutionParser solutionParser = new SolutionParser(SolutionPath);
SolutionElement solution = solutionParser.GetParsedSolution();
if (solution == null)
return;
Console.WriteLine("Done.");
foreach (ProjectElement project in solution.AllProjects)
foreach (SourceFile file in project.AllFiles)
foreach (TypeDeclaration type in file.AllTypes)
{
Console.Write(type.FullName);
Console.WriteLine(", members: " + ((ITypeElement)type).Members.Count);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
ParserHelper.UnRegisterParserServices();
}
Console.ReadLine();
}
If you put the sources into the "C:\Projects" folder and run the program without any arguments specified, you should see the following result:
Press the Enter key to close the window. Bear in mind, that the parsing process may take some time, so you might need to wait a few seconds, until the entire solution is parsed.
Related Topics
How to Change the Color of Winform Datagridview Header
Read from a File Starting at the End, Similar to Tail
Merge 2 Datatables and Store in a New One
Asynchronous File Download with Progress Bar
Htmlagilitypack - Remove Script and Style
Log Off User from Win Xp Programmatically in C#
C# Image.Clone Out of Memory Exception
Error: Must Create Dependencysource on Same Thread as the Dependencyobject Even by Using Dispatcher
How to Add an Item to a Listbox in C# and Winforms
Check If a Property Exists in a Class
Relative Path to Absolute Path in C#
C# Automatic Property Deserialization of JSON
Share Session Between Two Web Sites Using ASP.NET and State Server
C#: Detecting Which Application Has Focus
How to Copy Value from Class X to Class Y with the Same Property Name in C#
Different Forms of the Wcf Service Contract Interface
Expression-Bodied Function Members Efficiency and Performance in C# 6.0