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
If Not (projItems Is Nothing) 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