Native C++ documentation idea
- I have seen some messages asking about using sandcastle for native c++ documentation.
The main problem seem to be that the reflection data is not available.
I had an idea that the "reflection" information could be generated within the VS2005 environment. It shouldn't be very difficult to export the information from VS2005 into a reflection.org file.
To test the idea I took one of the VS addin examples and modifed it. Tested it on the following code:
------------
namespace Ns1 {
class Class1 {
void PrivateMember(int x) { }
public:
Class1() { }
int PublicMember() { return 0;}
};
namespace Ns2 {
class Class2 : public Class1 {
public:
Class2() { }
int Class2Member(Class1& y) { return 1; }
};
} // namespace ns2
} // namespace ns1
------
The output became like this
<class name="T:Ns1.Class1" visibility="public">
<elements>
<member name="M:Ns1.Class1.PrivateMember">
<arg name="x" type="T:int"/>
</member>
<member name="M:Ns1.Class1.Class1">
</member>
<member name="M:Ns1.Class1.PublicMember">
</member>
</elements>
</class>
<class name="T:Ns1.Ns2.Class2" visibility="public">
<ancestors>
<type name="T:Ns1.Class1"/>
</ancestors>
<elements>
<member name="M:Ns1.Ns2.Class2.Class2">
</member>
<member name="M:Ns1.Ns2.Class2.Class2Member">
<arg name="y" type="T:Ns1::Class1 &"/>
</member>
</elements>
</class>
I'm sure there are tons of problem to get the data to look like the reflection file generated by mrefbuilder but at least it is a start.
The program to do the above is ~60 lines.
public void ClassData(DTE2 dte) {
VCCodeModel cm = (VCCodeModel)dte.Solution.Item(1).CodeModel;
try {
sw = new System.IO.StreamWriter(@"c:\TEMP\reflectiondata.xml");
IterateChildren(cm.CodeElements);
}
finally {
sw.Close();
}
}
public void IterateChildren(CodeElements elems) {
for (int ii = 1; ii <= elems.Count; ++ii) {
if (elems.Item(ii).Kind == vsCMElement.vsCMElementNamespace)
IterateChildren(elems.Item(ii).Children);
else if (elems.Item(ii).Kind == vsCMElement.vsCMElementClass)
OutputClass((VCCodeClass)elems.Item(ii));
}
}
static public string FullName(VCCodeElement elem) { return elem.FullName.Replace("::","."); }
static public string Visibility(VCCodeElement elem) {
switch (((VCCodeClass)elem).Access) {
case vsCMAccess.vsCMAccessPrivate: return "private";
case vsCMAccess.vsCMAccessProtected: return "protected";
default: return "public";
}
}
public void OutputClass(VCCodeClass c) {
sw.WriteLine("<class name=\"T:" + FullName((VCCodeElement)c) + "\" visibility=\"" + Visibility((VCCodeElement)c) + "\">");
OutputBases(c.Bases);
sw.WriteLine("<elements>");
OutputMembers(c.Members);
sw.WriteLine("</elements>");
sw.WriteLine("</class>");
}
public void OutputBases(CodeElements bases) {
if (bases.Count >= 1) {
sw.WriteLine("<ancestors>");
for (int ii = 1; ii <= bases.Count; ++ii)
sw.WriteLine("<type name=\"T:" + FullName((VCCodeElement)bases.Item(ii)) + "\"/>");
sw.WriteLine("</ancestors>");
}
}
public void OutputMembers(CodeElements members) {
for (int ii = 1; ii <= members.Count; ++ii) {
sw.WriteLine("<member name=\"M:" + FullName((VCCodeElement)members.Item(ii)) + "\">");
OutputArguments(((CodeFunction)members.Item(ii)).Parameters);
sw.WriteLine("</member>");
}
}
public void OutputArguments(CodeElements args) {
for (int ii = 1; ii <= args.Count; ++ii)
sw.WriteLine("<arg name=\"" + args.Item(ii).Name + "\" type=\"T:" +
((CodeParameter)args.Item(ii)).Type.AsString + "\"/>");
}
Tutte le risposte
As long as you've got a source for the information about the classes and the members it is possible to produce a reflection information file for it. That's what AjaxDoc does for the JavaScript code.
Eric
Hi,
A few people have mentioned their interest in documenting unmanaged C++. I don't know C++ so I can't do it mysefl, but if you're willing to complete your converter then you can add it as a plug-in to DocProject, if you're interested:
DocProject: Creating a Build Engine Provider
http://www.codeplex.com/DocProject/Wiki/View.aspx?title=Creating+a+Build+Engine+Provider
If you need help with the reflection.org file format or DocProject's plug-in architecture, please ask and I'll try to help

- Dave
- I don't have the need for native c++ documentation myself so I have no plans of implementing it.
Also, when looking closer at the problem I don't think the sandcastle reflection file can handle native c++.
- There is no support for typedefs, templates, multiple inheritance etc.
- The xml documentation export doesn't work for templates. All template functions and classes are just ignored
(It might be possible to export it manually via the VS2005 CodeElement along with the reflection data)
- The name mangling of function names is non-trivial
typedef int* INT;
typedef std::vector<double>* VEC;
int func(INT* x, const VEC& y)
becomes:
<member name="M:func(System.Int32**,std.vector<System.Double>*!System.Runtime.CompilerServices.IsConst*!System.Runtime.CompilerServices.IsImplicitlyDereferenced)"> Hi,
Some good points, however the schema of the reflection file and poor XML documentation aren't really bottlenecks. AFAIK, Sandcastle wasn't designed to generated documentation for native C++, in particular, however it was designed to be flexible enough to do so through customization.
- There is no support for typedefs, templates, multiple inheritance etc.
Support could be added by adding custom elements/attributes like the VS and Prototype doc model transformations do, but that would also require modifications to the presentation styles so that they will actually use the new data. And this should be expected since Sandcastle doesn't document native C++ out-of-the-box.
- The xml documentation export doesn't work for templates. All template functions and classes are just ignored
(It might be possible to export it manually via the VS2005 CodeElement along with the reflection data)
- The name mangling of function names is non-trivialThese problems are cause by flaws in the C++ compiler that produces XML documentation, but since it will not affect reflection information generated by a custom solution I don't think this is a showstopper. It's possible that some people would still like to have at least the skeleton documentation generated so that they can write the XML documentation externally, for example, using Visual Studio's XML editor or DocProject's XML documentation editor.
- Dave
- Spent more time on this than I planned but tested a few things and it looks like it is possible to extract the xml doc information as well. The tricky part will be to look up the cref tags.
Lets say that I can create reflection.org and a doc.xml file. I would need help to get it to work with sandcastle.
To get any useful information I also need to modify the name mangling slightly. Is it possible to do like this without creating a lot of changes in sandcastle
- Typedefs get a new subgroup (or another prefix like "D:"?)
- templates use the generics naming but with parameters in the name so specializations are different "T : std.vector'2{T1,T2}"
, "M : std.vector'2{int, T2).begin"
- Don't know how to handle c++ type modifiers. The problem is how sandcastle should know that "MyType", "MyType*", "const MyType* const*" all refer to the same type and should be linked to the same page. Same problem with const member overloads (maybe just a "#const" at the end)
Since I create the doc xml file myself there is no problem to ensure that the names match the reflection names. What you have is going in the right direction.There should be any changes needed to Manifold core tools such as MrefBuilder, links resolver.
However I do see changes needed in Document model and presentation transforms. Please allow me some time to think about this as I am interested in released an unmanaged component for Sandcastle.
Anand..
- I actually got it working.
The VS2005 plugin generates reflection.org and comments.xml which are fed directly to sandcastle (just commented out mrefbuilder in the example build_sandcastle.bat file)
The C++ code below worked fine except the typedefs.
namespace namespace1 {
/// <summary>Documenting typedef INT</summary>
typedef int INT;
/// <summary>A base class</summary>
class Class1 {
public:
/// <summary>Public typedef</summary>
typedef Class1 this_type;
/// <summary>Private constructor</summary>
Class1(int arg1);
protected:
/// <summary>Protected constructor</summary>
Class1(int arg1, int arg2);
public:
/// <summary>Public constructor</summary>
Class1(int arg1, int arg2, int arg3);
private:
/// <summary>Private void member</summary>
void Member1();
public:
/// <summary>Protected const void member2</summary>
void Member2() const;
/// <summary>Public overloaded int member3</summary>
int Member3(int arg1);
/// <summary>Another overload</summary>
int Member3(int arg1, int arg2);
/// <summary>Const overload</summary>
int Member3(int arg1) const;
/// <summary>reference argument overlaod</summary>
int Member3(int& arg1);
/// <summary>static member</summary>
static int Member4();
/// <summary>virtual member</summary>
virtual int Member5();
/// <summary>abstract member</summary>
virtual int Member6() = 0;
/// <summary>virtual destructor</summary>
virtual ~Class1();
};
namespace namespace2 {
/// <summary>Struct with public inheritance</summary>
struct Class2 : public Class1 {
/// <summary>Public typedefs</summary>
typedef Class1 base_type;
/// <summary>Constructor</summary>
Class2();
/// <summary>Override member</summary>
int Member2() const;
/// <summary>virtual override</summary>
virtual int Member6();
/// <summary>Normal destructor</summary>
~Class2();
};
} // namespace2
} // namespace namespace1 Hi,
The tricky part will be to look up the cref tags.
That might be tricky, but it's not entirely necessary either - at least not for preliminary support.
Lets say that I can create reflection.org and a doc.xml file. I would need help to get it to work with sandcastle.From your last post is seems like you already got it working, but if you need any more help let us know

To get any useful information I also need to modify the name mangling slightly. Is it possible to do like this without creating a lot of changes in sandcastleIt may be better to format them using a regular expression. If there's any extra data that has no use in Sandcastle presentations then removing it before build assembler runs could increase performance slightly of the XPath expressions and reduce the size of the reflection.org file. A regex will also allow you to format the data to make your XPath expressions simpler and more readable. Of course, it doesn't have to be done with a regex though.
- Typedefs get a new subgroup (or another prefix like "D:"?)This will require new XSL in the Sandcastle presentations to read the data and place it somewhere in the topic. The XPath to match an id with a "D:" prefix or a different subgroup type should be fairly simple I think.
- templates use the generics naming but with parameters in the name so specializations are different "T : std.vector'2{T1,T2}"
, "M : std.vector'2{int, T2).begin"I'm not sure what a specialization is, but I assume that it's the same as a "bounded" generic in the managed world? If that's the case, bounded generics are not documented by Sandcastle since they do not appear in the reflection file - they are generated by the CLR. I'm pretty sure that the compiler handles generics in C++, correct? If that's the case then a new topic type would have to be created (using XSL).
- Don't know how to handle c++ type modifiers. The problem is how sandcastle should know that "MyType", "MyType*", "const MyType* const*" all refer to the same type and should be linked to the same page. Same problem with const member overloads (maybe just a "#const" at the end)If they should link to the same page then the extra information should not be present in the reflection data or XML comments. A regex could clean up that stuff before handing the files over to Sandcastle.
- Dave
- Hello,
I am also trying to use sandlecastle for generating documentation of some unmanaged code in VC++. Is it possible for you to share the plug-in source code for generating the required org and xml files?
Thank you in advance.
Jagat.

