Project Cleaner

While the VS.NET IDE is very nice, the project models for VisualC# and
Visual Basic.NET lack several capabilities. One of those is providing a “Clean” build option
that deletes intermediate and output files from a project/solution.

So I set out to build a VS.NET AddIn that provided this capability. The result is
ProjectCleaner, a simple AddIn that will give you a "Clean Project" option when you
right-click on a project in solution explorer, or a "Clean Solution" option when you right-click
on a solution.

In building it, however, I ran into several gotchas, which I wanted to explain here in case
anybody else runs into them.

Solution Explorer

In order to provide a "Clean Project" option, I needed to detect on which project node the user
had right-clicked in the Solution Explorer window. I found this to be non-intuitive. To do so, you use the
SelectedItems property of the _DTE object, like this:


private Project GetSelectedProject() 
{
   SelectedItems items = AppObject.SelectedItems;
   Debug.Assert(items.Count==1, "Incorrect number of selected items");

   return items.Item(1).Project;
}

This, of course, assumes you do this when you get the command invocation; it won't work on other contexts.

Output Groups

Each project has a collection of OutputGroup object, each of one represents a collection of files.
However, the name is really misleading, because the OutputGroups collection includes groups that are not
outputs of the project, but also inputs. In the case of the C# and VB.NET project models,
you'll encounter one group called "SourceFiles" which includes the list of source files
in the project.

Another weird thing is that an OutputGroup object includes two properties: FileNames and FileURLs.
Contrary to what the documentation says, it seems that the FileNames property only lists filenames with paths
relative to the project's directory, not the full path. And in the case of the FileURLs property, which does
give you full paths (in the form of file://c:\.....), it has one extra glitch: If you're looking at an
OutputGroup representing the produced binaries (like the "Built" group), you'll see that this path
points you into the intermediate directory (the obj/ dir), and not into the real output directory (the bin/ dir).

Another limitation is that there is no OutputGroup
representing the project's references that had the "Local Copy" property set to
true. To get these, you need to add a reference to your AddIn project to the
VSLangProj assembly. Once you've done that, you can cast the Object property of
your Project instance to a variable of the type VSProject. This object will
include a References collection with all project references. You can then check
the CopyLocal property for each each Reference object in it to find if you need
to delete it.

This still has one minor limitation: The Reference.Name
property only lists the assembly simple name, without extension, which means you
kind of have to assume it is a known value. There's also no way to find out if
VS.NET copied a debug info file (.pdb) alongside with the referenced assembly.

You can check the code that deals with this inside the
InternalCleanProject(), DeleteFilesInGroup() and DeleteReferenceCopy() methods
of the ProjectCleaner class.

Commands

I finally was able to delete commands previously created.
The trick is that to reference a command your AddIn created, you need to use the
full name of it when calling the Commands.Item() method. For example, if my
AddIn adds a command named "CleanProject", the full name of the command will be
"ProjectCleaner.Connect.CleanProject".

Final Notes

Keep in mind that it
is an early version, so be sure to have backups of your data before trying it. I assume no
responsibility for
what might go wrong. Also, notice that this version has two limitations: It is harsh, and
might completely delete your
project's bin and obj directories, and won't do anything in C++ projects. I hope to improve
this situation somewhat in the near future.

Updated: 01/29/2002. Thanks to Craig Skibo from
Microsoft for helping me out figure a couple of things!

You can download ProjectCleaner's source code here.

You can download an MSI installation with ProjectCleaner's
binaries for VS.NET RTM here (notice it doesn't include the framework or MSI 2.0
bootstrapper).

Updated: 02/01/2002. Chris Sells pointed out to me a couple of things that weren't working
on the MSI installer. Those are now fixed. Also, you can now find a new options dialog in the VS.NET
Tools->Options dialog, under the Winterdom folder. This switch allows you to use the new behavior
(delete only project output groups and local references), or delete all files in the output
and intermediate directories. (I suggest using the MSI installation, the source distribution
doesn't contain the merge file needed to create the appropriate registry entries for this to happen).