Enumerating projects in a Visual Studio solution
People writing add-ins for Visual studio probably have come across the nightmare of the Visual studio object model to go through the projects within a solution. I had to get the list of projects in a solution, and for each solution its output path in the current configuration. Although I need the code in C# later on, the best way to check out how to program against the Visual Studio object model is within the Macro IDE of Visual Studio (Tools->Macros->Macros IDE).
Although the question seems quite straightforward, the trouble begins when you have Solution Folders containing projects. The Solution object has a property called Projects, but Solution Folders are also seen as Projects. A project has project items. A project item can be a folder, a file, or... a project. You have to see it to believe the mess.
After a lot of trial and error I got to a solution where I check if a project item has its ConfigurationManager property set, if this is the case, it must be a project. Not sure if this is the best approach, but it works for me. For example for the following project structure using Solution Folders:
I get the following output:
And the code to accomplish this (paste in Macros IDE):
Sub SolutionProjects() Dim project As EnvDTE.Project Write("--------- DUMP OF ALL PROJECTS IN CURRENT SOLUTION -------------") Try If Not DTE.Solution.IsOpen Then Write("There is no solution open.") Else For Each project In DTE.Solution.Projects NavProj(project) Next End If Catch ex As System.Exception Write(ex.ToString) End Try End Sub Sub NavProj(ByVal proj As Project) Dim outputPathProperty As EnvDTE.Property Dim outputPath As String If Not (proj.ConfigurationManager Is Nothing) Then ' It's a project! outputPathProperty = _ proj.ConfigurationManager.ActiveConfiguration.Properties.Item("OutputPath") If outputPathProperty Is Nothing Then outputPath = "<no output path set>" Else outputPath = outputPathProperty.Value End If Write("### Project: " + proj.Name + ", OutputPath: " + outputPath) Else NavProjItems(proj.ProjectItems) End If End Sub Sub NavProjItems(ByVal projItems As ProjectItems) Dim projectItem As EnvDTE.ProjectItem<span style="color: rgb(0,0,255)">If</span> <span style="color: rgb(0,0,255)">Not</span> (projItems <span style="color: rgb(0,0,255)">Is</span> <span style="color: rgb(0,0,255)">Nothing</span>) <span style="color: rgb(0,0,255)">Then
For Each projectItem In projItems If Not (projectItem.SubProject Is Nothing) Then ' Recurse, can be an Enterprise project in ' Visual Studio .NET 2002/2003 or a solution folder in VS 2005 NavProj(projectItem.SubProject) End If Next End If End Sub
Sub Write(ByVal s As String) Dim out As OutputWindowPane = GetOutputWindowPane("MACRO OUTPUT", True) out.OutputString(s) out.OutputString(vbCrLf) End Sub
Function GetOutputWindowPane(ByVal Name As String, Optional ByVal show As Boolean = True) As OutputWindowPane Dim win As Window = DTE.Windows.Item(EnvDTE.Constants.vsWindowKindOutput) If show Then win.Visible = True Dim ow As OutputWindow = win.Object Dim owpane As OutputWindowPane Try owpane = ow.OutputWindowPanes.Item(Name) Catch e As System.Exception owpane = ow.OutputWindowPanes.Add(Name) End Try owpane.Activate() Return owpane End Function