
Introduction
After many many years away from software development I decided to take the leap and rekindle my interest. Wow and have things changed! Having purchased a copy of Visual Studio and electing to go with C# my simple application grew and grew which screamed for a level of documentation due to my "put down pick up" approach. I initially used the bundled "Build Comment Web Pages" add-in which I liked but found it very verbose generating a multitude of pages and hence the presented lean and mean code documentation program.
Background
In developing this application I was exposed to many new aspects of the Visual Studio .NET development environment some were relatively easy to address either through MSDN or web sites such as CodeProject. Areas which were either picked up by chance or required a suck and see it approach included debugging Visual Studio add-in code, access to the DTE environment and TreeNode tags. I have captured some of my experiences related to these areas in the following section.
Using the code
To add the VShtmlhelp add-in to the Tools menu install VShtmlhelpSetup either using the Install function from the Solution Explorer or running directly the VShtmlhelpSetup.msi file. To complete registration double click the ReCreateCommands.reg file. The smiley icon VShtmlhelp will now be displayed in the Tools menu. Selecting this for the VShtmlhelp project will produce the above dialog while selecting the build button will produce the following HTML file output.

Debugging Visual Studio add-in code is possible be it a bit tedious. After several hours of searching and experimenting the approach I used was as follows:
- Open Visual Studio and in the start page select New Project to create the add-in.
- Select Extensibility Projects under project type and then Visual Studio .NET Add-in under templates.
- Enter a name for your add-in then select OK button whereupon the add-in wizard dialog will be displayed.
- Step through the wizard recommended actions, beyond defaults deselect VSMacros tick box and select tick box for ‘Tools’ menu item.
- After creating your add-in project open the connect.cs file within the Solution Explorer.
- While developing and before your run your add-in for the first time - within the connect.cs file comment out the
if ConnectMode = …
statement within the OnConnection
method, within the connect.cs file add the following to the OnDisconnection
method (C# code shown, remember to enter the name of your Add-in on line 6):
Commands commands = applicationObject.Commands ;
try
{
Command command =
commands.Item("YourAddin.Connect.YourAddin", -1);
command.Delete();
}
catch(System.Exception)
{
MessageBox.Show ("Add-in OnDisconnection failure");
}
As this code uses MessageBox
add System.Windows.Forms
to References in the Solution Explorer and as a Using
statement within the connect.cs file, now build your code. When debugging, on the toolbar select Tools Add-in Manager.. identify your add-in and tick the startup box, prior to closing Visual Studio reverse this action. You are now able to develop and debug your add-in remember to reverse the above code changes once you are ready to release your code.
Visual Studio .NET provides tools for extending and automating the integrated development environment (IDE). DTE stands for Development Tools Extensibility and the DTE Object model presents a structured set components for the Visual Studio .NET runtime environment. This object model enables access and modification of different components which includes Solution, Projects and Project Items. The following sample code writes the Solution name into a label solutionNameLbl
:
using EnvDTE;
public _DTE dteApplication;
private void HelpDialog_Load(object sender,
System.EventArgs e)
{
EnvDTE.Solution dteSolution =
dteApplication.Solution;
solutionNameLbl.Text = dteSolution.FullName;
}
Through the use of a foreach
statement you are able to iterate through each Project within the Solution. The following sample loads each Project name into a ListBox projectsLst
:
foreach (Project project in dteSolution.Projects)
{
if (project.ProjectItems != null)
{
projectsLst.Items.Add(project.Name);
if (!projSelected)
{
projectsLst.SetSelected(0, true);
projSelected = true;
}
}
}
Once you have the Project you are able to get a count of the ProjectItems
within the Project. The following code is an extract from the function ProjectItems
which iterates through each projectItems
thereby obtaining the FileCodeModel
and then calling iterateFileCodeModel
:
for (int r = 1; r< project.ProjectItems.Count +1; r++)
{
projectItem = project.ProjectItems.Item(r);
fileCode = projectItem.FileCodeModel;
if (fileCode != null)
{
iterateFileCodeModel(fileCode, filesTrv);
}
}
The FileCodeModel
object enables the user to find any code element within the Project given a fully qualified name. By using the Kind
function and enumerator vsCMElement
39 elements can be identified including namespace, class, property, variable and function. The following extract from iterateFileCodeModel
demonstrates this, it also shows the construction of the TreeView filesTrv
. This construction consists of the namespace followed by the classes associated with the namespace, it uses the Tag
function allowing namespace or class element data to be assigned to the associated TreeNode. This has the benefit that when the user selects the relevant Project and subsequently the Build button the HTML pages can be derived directly from the TreeView filesTrv
.
if (codeElement.Kind == vsCMElement.vsCMElementNamespace)
{
nameSpaceNodeIndex =
NameSpaceNode(codeElement.FullName, filesTrv);
if (nameSpaceNodeIndex == -1)
{
nameSpaceNode =
filesTrv.Nodes.Add(codeElement.FullName);
nameSpaceNode.Tag = codeElement;
}
else
nameSpaceNode =
filesTrv.Nodes[nameSpaceNodeIndex];
foreach (CodeElement cdClassElmnt in
((CodeNamespace)codeElement).Members)
{
if(cdClassElmnt.Kind ==
vsCMElement.vsCMElementClass)
{
TreeNode classNode =
nameSpaceNode.Nodes.Add(cdClassElmnt.Name);
classNode.Tag = cdClassElmnt;
}
}
}
The HTML page consists of three frames - left, main and top pages. The top page is static whereas the left and main pages are dynamic depending on the built project. Once the build is activated the TreeView filesTrv
is used to generate the index left page and as each class is added a main page (ClassXX.htm) is created by calling the function WriteClassDetail
. This function is passed the classes TreeNode and using the Tag
function the codeElement
is recovered. The codeElement
's codeType
count is used to iterate through each function whereby the necessary data is extracted to construct the HTML class main page, as shown below:
for (int i = 0; i < codeType.Members.Count; i++)
{
codeElement = codeType.Members.Item(i+1);
if (codeElement.Kind == vsCMElement.vsCMElementFunction)
{
CodeFunction codeFunction = (CodeFunction)codeElement;
editPoint.MoveToPoint(codeFunction.GetStartPoint(
vsCMPart.vsCMPartHeader));
functionStr = editPoint.GetLines(editPoint.Line,
editPoint.Line+1);
summaryStr = SearchAndCut(codeFunction.DocComment,
"<SUMMARY>", "</SUMMARY>");
Console.SetOut(swc);
swc.Write(TABLEROW);
swc.Write(TABLEWIDTH);
swc.Write(TABLEINPUTSPACE);
swc.Write(TABLEINPUTTOP, codeFunction.Name);
swc.Write(TABLEINPUTFUN, functionStr, summaryStr);
swc.Write(TABLEWIDTH);
swc.Write(TAGTR);
}
}
History
- 6th August, 2005 - Initial version.