HtmlHelp
A Visual Studio add-in that produces compact HTML code documentation from embedded XML

Introduction
As Visual Studio applications grow the importance of documentation
for support and maintenance becomes paramount. The Visual Studio bundled "Build
Comment Web Pages" add-in
although acceptable is very verbose, generating a
multitude of pages and hence the following lean and mean code documentation
program.
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:
1. Open Visual Studio and on the start page select New Project to create the
add-in.
2. Select Extensibility Projects under project type and then Visual Studio
.NET Add-in under templates.
3. Enter a name for your add-in then select OK button whereupon the add-in
wizard dialog will be displayed.
4. Step through the wizard recommended actions, beyond defaults deselect VSMacros
tick box and select tick box for ‘Tools’ menu
item.
5. After creating your add-in project open the connect.cs file within the solution
explorer.
6. 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 YourAddin on line 6):
// Dev/Debug code, get the commands collection. Commands commands = applicationObject.Commands ; try { // Delete the required command. 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 loading each Project name
into a listbox projectsLst:
foreach (Project project in dteSolution.Projects) { // if project does not contain valid code then ignore the project entry if (project.ProjectItems != null) { projectsLst.Items.Add(project.Name); if (!projSelected) { // generates projectsLst_SelectedIndexChanged event 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 projectItem thereby obtaining the FileCodeModel
and then calling iterateFileCodeModel:
// For the selected Project Cycle each project item. for (int r = 1; r< project.ProjectItems.Count +1; r++) { projectItem = project.ProjectItems.Item(r); // Get the file code model fileCode = projectItem.FileCodeModel; // valid file if not a null if (fileCode != null) { // Cycle through the file code model 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 that the html pages can be derived directly from the TreeView
filesTrv.
if (codeElement.Kind == vsCMElement.vsCMElementNamespace) { // Generate new namespace node if index 0 otherwise use existing node nameSpaceNodeIndex = NameSpaceNode(codeElement.FullName, filesTrv); if (nameSpaceNodeIndex == -1) { nameSpaceNode = filesTrv.Nodes.Add(codeElement.FullName); //Tag the code element to the node, to be used by HTML page generation. 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); //Tag the class element to the node, to be used by HTML page generation. classNode.Tag = cdClassElmnt; } } }
The html page consist of 3 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 function WriteClassDetail.
This function is passed the classes TreeNode and using the Tag function
the codeElement is recovered.
The codeElements 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.
// Iterate through each of the classes functions for (int i = 0; i < codeType.Members.Count; i++) { codeElement = codeType.Members.Item(i+1); if (codeElement.Kind == vsCMElement.vsCMElementFunction) { CodeFunction codeFunction = (CodeFunction)codeElement; // Move edit point to function definition editPoint.MoveToPoint(codeFunction.GetStartPoint(vsCMPart.vsCMPartHeader)); // Get function method statement functionStr = editPoint.GetLines(editPoint.Line, editPoint.Line+1); // Get summary statement summaryStr = SearchAndCut(codeFunction.DocComment, "", ""); 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); } }
 |