CHAPTER 8
In this chapter, we are going to create an add-in module to explore the current solution open in the IDE, and present a summary screen of some key statistics about the solution. It provides a basic example of how to programmatically access various aspects of the solution.
Start your Solution Info add-in using the wizard and the following settings:
Verify the settings at the Summary screen, and if they look okay, generate the code.
To help distinguish our add-in a bit, we are going to change the default icon to the lightbulb symbol. You can add the constant to the top of your connect.cs class file:
const int LIGHTBULB_ICON = 1000; |
And revise the OnConnection method to use this constant, rather than the hard-code 59 the wizard generates.
|
Command command = commands.AddNamedCommand2(_addInInstance, "SolutionInfo", "Solution Info", "Info & Statistics about solution", true, LIGHTBULB_ICON, ref contextGUIDS, (int)vsCommandStatus.vsCommandStatusSupported + (int)vsCommandStatus.vsCommandStatusEnabled, (int)vsCommandStyle.vsCommandStylePictAndText, VsCommandControlType.vsCommandControlTypeButton); |
The Exec() method will collect a variety of solution information and present it to the user. But first, we need to make sure a solution is open.
|
// Only makes sense if a solution is open. if (_applicationObject.Solution.IsOpen==false) { MessageBox.Show("No solution is open","ERROR"); handled = true; return; } |
Note: Be sure to add a reference to System.Windows.Forms to your project.
We can now use the Solution object to explore some aspects of the currently open solution. We will use a similar approach of building the information in a string builder variable and then transferring the text to our GUI form. In the following code sample, we are taking some of the simple properties of the solution object and displaying them:
|
StringBuilder sb = new StringBuilder(); Solution theSol = _applicationObject.Solution; sb.AppendLine(" Solution: " + Path.GetFileName(theSol.FullName.ToString())); sb.AppendLine(" Full Path: " + theSol.FullName.ToString()); sb.AppendLine("Start-up projects: "); foreach (String s in (Array)theSol.SolutionBuild.StartupProjects) { sb.AppendLine(" " + s); } |
We also want to report on the number of projects and code files the solution contains. To do so, we need to iterate through the projects associated with the solution.
|
Project theProj; // Generic project item. int NumVBprojects = 0; int NumVBmodules = 0; int NumCSprojects = 0; int NumCSmodules = 0; int NumOtherProjects = 0; // Iterate through the projects to determine number of each kind. for (int x = 1; x <= theSol.Count; x++) { theProj = theSol.Item(x); switch (theProj.Kind) { case PrjKind.prjKindVBProject : { NumVBprojects++; // Increment number of VB projects. NumVBmodules += theProj.ProjectItems.Count; break; } case PrjKind.prjKindCSharpProject : { NumCSprojects++; // Increment number of C# projects. NumCSmodules += theProj.ProjectItems.Count; break; } default: { NumOtherProjects++; break; } } } |
The Kind property of the project object is a GUID string, so we need a little help in determining the project type. To this end, we need to add a reference to VSLangProj into our add-in project.
You might see a compiler error stating that prjKind cannot be embedded when you attempt to reference the project kinds. To solve this error, right-click on the VSLangProj reference and bring up the Properties dialog. Set the Embed Interop Types to false to prevent the types from being embedded in the assembly.
Now that we’ve collected the information, we need to format it for display to our user, which the following code sample shows:
|
sb.AppendLine("Visual Basic code"); sb.AppendLine(" " + NumVBprojects.ToString() + " projects containing " + NumVBmodules.ToString() + " modules"); sb.AppendLine(""); sb.AppendLine("Visual C# code"); sb.AppendLine(" " + NumCSprojects.ToString() + " projects containing " + NumCSmodules.ToString() + " modules"); sb.AppendLine(""); sb.AppendLine("Miscellaneous projects"); sb.AppendLine(" " + NumOtherProjects.ToString() + " other projects"); sb.AppendLine(""); |
Project GUIDS are stored in a registry key, HKLM\Software\Microsoft\VisualStudio\<vers> Projects. You can copy the GUID to additional constants if you need to report on other project types during the Solution add-in. The following are some sample constants for VS projects:
|
// Constants for additional project types. const string WEB_APPLICATION_PROJECT = "{E24C65DC-7377-472b-9ABA-BC803B73C61A}"; const string DEPLOYMENT_PROJECT = "{54435603-DBB4-11D2-8724-00A0C9A8B90C}"; |
After we’ve gathered some of the solution info, we can iterate through the properties associated with the solution, and append them to our string builder variable.
|
// Get properties. sb.AppendLine("Solutuion Properties"); Properties props = theSol.Properties; foreach (Property prop in props) { sb.Append(" " + prop.Name + " = "); try { sb.AppendLine(prop.Value.ToString()); } catch { sb.AppendLine("(Nothing)"); } } // Put built string onto form. SolInfoForm theForm = new SolInfoForm(); theForm.SOLINFO.Text = sb.ToString(); theForm.ShowDialog(); handled = true; return; |
After we’ve built our string builder variables, we need to create a form to display them to the end user.

You can download the project code or create your own form similar to the one in Figure 12. The add-in code assumes the text box control is named SOLINFO. Be sure to name it the same and mark its modifier as PUBLIC so the add-in can place the solution information on the form.
In addition to displaying information about the solution, you can also perform certain operations on the solution, much like the IDE does. Some of these include:
This method closes the solution, with an optional Boolean parameter to save the solution first.
This method searches the project space, looking for an item by file name. If the item is found, the method returns a ProjectItem reference to the file you were searching for.
This method allows you to save the solution under a different file name.
The solution object also provides information about the active configuration and the last build state. You can use the Solution Build object of the solution to perform solution-level operations, such as:
Build the solution with an optional parameter to wait for the build to complete. You might decide to do automated solution builds in the background as part of your testing cycle.
This method cleans up extra files used by the solution, and features an option to wait for completion before continuing.
This option runs the start-up project associated with the solution.
This property reports the current state of the build and is an enumerated type from the following list: