I usually work with a pretty large VS.NET solution. Currently It contains 60 projects and I don't need them all of the time. To ease the solution loading and help VS.NET add-ins like ReSharper load and function faster, it is a good idea to split this solution into several smaller ones. Since the projects interdependencies are not that simple, I decided to automate the process of creating the smaller solutions.
The macro below finds all projects referenced of the selected ones and removes the other projects from the solution. Then you one can do "Save as" and use the shrinked solution. Use ShowAllReferencedProjects() for displaying the projects that will remain after the operation and RemoveAllProjectsUnusedByActiveProjects() for the actual removal (you will be asked if you are sure you want to do that).
Note: Excuse my VB, I have not exercised my VB skills, since doing some VB6 coding more than two years ago. The part that was most fun and challenging was not VB, but exploring the VS.NET object model - surprisingly the resources on this topic were a little scarce.
Disclaimer: Use the code at your own risk! (well, it can't really do much harm, since it does not save the solution automatically).
UPDATE: Well, actually RemoveAllProjectsUnusedByActiveProjects() can affect some of the project files, since the order of removal turned out to be important (removing a referenced projects, shortens the reference lists of other project). This issue is fixable, but currently I don't have the time to fix it :) Moreover the operation is very slow so it might be easier to add projects to a blank solution instead of removing them from existing solution. Actually, the best way to handle this task is on a file level, where you need a parser for solution and project files. Parsing those files will not be that trivial and I had not been able to find such parsers online. Looks like a good idea for a pet project :)
Imports System
Imports EnvDTE
Imports EnvDTE80
Imports System.Collections.Generic
Imports System.Diagnostics
Imports System.Windows.Forms
Public Module VsProjectsManagement
Public Sub RemoveAllProjectsUnusedByActiveProjects()
Dim unusedProjects As List(Of VSLangProj.VSProject) = FindAllProjectsUnusedByActiveProjects()
If unusedProjects.Count = 0 Then
MessageBox.Show("There are no unused projects for the current project selection")
Exit Sub
End If
Dim s As String
s = "Do you want to remove the following " & unusedProjects.Count & " projects from the solution: " _
& GetProjectNames(unusedProjects) & "?"
If Not DialogResult.Yes = MessageBox.Show(s, "Unused projects removal", MessageBoxButtons.YesNo, MessageBoxIcon.Question) Then
Exit Sub
End If
RemoveProjectsFromSolution(unusedProjects)
End Sub
Public Sub ShowAllReferencedProjects()
Dim usedProjects As List(Of VSLangProj.VSProject)
usedProjects = FindAllProjectsReferencedByActiveProjects()
Dim s As String
s = "The selected project(s) reference total of " & CStr(usedProjects.Count) _
& " projects in the solution: " & GetProjectNames(usedProjects)
MessageBox.Show(s, "Referenced projects")
End Sub
Sub RemoveProjectsFromSolution(ByVal projects As List(Of VSLangProj.VSProject))
For Each vsProject As VSLangProj.VSProject In projects
DTE.Solution.Remove(vsProject.Project)
Next
End Sub
Function GetProjectNames(ByVal projects As List(Of VSLangProj.VSProject)) As String
Dim projectNames As List(Of String) = New List(Of String)(projects.Count)
For Each vsProject As VSLangProj.VSProject In projects
projectNames.Add("'" & vsProject.Project.Name & "'")
Next
projectNames.Sort()
Return String.Join(", ", projectNames.ToArray())
End Function
Function FindAllProjectsUnusedByActiveProjects() As List(Of VSLangProj.VSProject)
Dim allVsProjects As List(Of VSLangProj.VSProject)
Dim vsProject As VSLangProj.VSProject
allVsProjects = FindAllVsProjectsInSolution()
If (allVsProjects.Count = 0) Then
Debug.WriteLine("There are no Projects In Solution")
Exit Function
End If
Dim allActiveAndReferencedProject As List(Of VSLangProj.VSProject)
allActiveAndReferencedProject = FindAllProjectsReferencedByActiveProjects()
Return DifferenceProjects(allVsProjects, allActiveAndReferencedProject)
End Function
Function DifferenceProjects(ByVal mainSet As List(Of VSLangProj.VSProject), ByVal setToRemove As List(Of VSLangProj.VSProject)) As List(Of VSLangProj.VSProject)
Dim resultSet As New List(Of VSLangProj.VSProject)
For Each vsProject As VSLangProj.VSProject In mainSet
If Not setToRemove.Contains(vsProject) Then
resultSet.Add(vsProject)
End If
Next
Return resultSet
End Function
Function FindAllProjectsReferencedByActiveProjects() As List(Of VSLangProj.VSProject)
Dim activeVSProjects As List(Of VSLangProj.VSProject)
Dim allActiveAndReferencedProject As New List(Of VSLangProj.VSProject)
Dim vsProject As VSLangProj.VSProject
activeVSProjects = FindAllActiveVsProjects()
If (activeVSProjects.Count = 0) Then
Debug.WriteLine("Please select one or more projects in the solution")
Exit Function
End If
' fill first the initial selected projects
For Each vsProject In activeVSProjects
allActiveAndReferencedProject.Add(vsProject)
Next
' find all referenced projects recursively
For Each vsProject In activeVSProjects
FindAndFillReferencedProjects(vsProject, allActiveAndReferencedProject)
Next
Return allActiveAndReferencedProject
End Function
Function FindAllVsProjectsInSolution() As List(Of VSLangProj.VSProject)
Dim usedVSProjects As New List(Of VSLangProj.VSProject)
For Each proj As Project In DTE.Solution.Projects
If TypeOf proj.Object Is VSLangProj.VSProject Then
usedVSProjects.Add(proj.Object)
End If
Next
Return usedVSProjects
End Function
Function FindAllActiveVsProjects() As List(Of VSLangProj.VSProject)
Dim usedVSProjects As New List(Of VSLangProj.VSProject)
For Each proj As Project In DTE.ActiveSolutionProjects()
If TypeOf proj.Object Is VSLangProj.VSProject Then
usedVSProjects.Add(proj.Object)
End If
Next
Return usedVSProjects
End Function
Sub FindAndFillReferencedProjects(ByVal objVSProject As VSLangProj.VSProject, ByVal usedVSProjects As List(Of VSLangProj.VSProject))
Dim referencedVSProject As VSLangProj.VSProject
Dim proj As Project
For Each objReference As VSLangProj.Reference In objVSProject.References
If objReference.Type = VSLangProj.prjReferenceType.prjReferenceTypeAssembly Then
proj = objReference.SourceProject
If Not proj Is Nothing Then
If TypeOf proj.Object Is VSLangProj.VSProject Then
referencedVSProject = proj.Object
If Not referencedVSProject Is Nothing Then
If Not usedVSProjects.Contains(referencedVSProject) Then
' Add current and recursively add the others
usedVSProjects.Add(referencedVSProject)
FindAndFillReferencedProjects(referencedVSProject, usedVSProjects)
End If
End If
End If
End If
End If
Next
End Sub
End Module
Labels: vs.net