How to build CHM / HTML Documentation with Sandcastle September CTP 2007 and NANT

The new Sandcastle CTP isn’t well documented at all and the documentation that can be found is useless, because the Sandcastle September CTP 2007 changed alot compared to old CTPs for that the documentation has been written. So I had to search about several hours to get my first CHM Documentation file automatically created with a NANT target. But step by step.

You first have to check some pre-requisites, before continueing.

  1. You have to install NANT version 0.85, if you don’t already have. (
  2. You have to install the Sandcastle September CTP 2007. (
  3. After Installation check your environment variable DXROOT. It must point to the new installation directory of the Sandcastle September CTP. My environment still pointed to the old Sandcastle version, which leads to some failures.
  4. Open the commandline of windows (cmd.exe) and go into the installation directory of Sandcastle September CTP, subfolder “Examples\Sandcastle” and run “build_sandcastle.bat vs2005 test“. This creates reflection files for the complete .NET Framework. This takes probably a few minutes. So be patient.
  5. You have to install the Html Help Workshop (htmlhelp.exe –

Now we can create a small example “Hello World” solution. To do this, simply create a new console application project with VS 2005 and store it to your preffered destination. Don’t forget to make the members public, otherwise you won’t get any result.

/// <summary>
/// This is a hello world example
/// </summary>
public class Program
    /// <summary>
    /// That's a small "Hello World" solution.
    /// </summary>
    /// <param name="args"></param>
    public static void Main(string[] args)
        Console.WriteLine("Hello World.");

As second you should not forget to specify a XML Documentation file in your Visual Studio project properties (Page Build). Because if not, you won’t see any custom comments.

Setting the XML Documentation file

Let us now create a simple NANT Script that executes the Sandcastle Creation Process.

<?xml version="1.0"?>
<project name="HelloWorld" default="build" basedir=".">

<property name="framework.dir" value="C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727"/>
<property name="solution.file" value="HelloWorld" />
<property name="solution.output" value="HelloWorld\bin\debug\HelloWorld.exe"/>
<property name="solution.comments" value="HelloWorld\bin\debug\HelloWorld.xml"/>

<include buildfile="Sandcastle.include"/>

/// <!-- Build means, compile and document -->
<target name="build" depends="compile, Sandcastle.Doc" />

/// <!-- Compile sourcecode using msbuild -->
<target name="compile">

<exec program="${framework.dir}\msbuild.exe" commandline='"${solution.file}.sln" /t:Rebuild /p:Configuration=Debug'/>
<exec program="${framework.dir}\msbuild.exe" commandline='"${solution.file}.sln" /t:Rebuild /p:Configuration=Release'/>



As you can see, the only thing to do is to call the Sandcastle.Doc target and to set the correct solution properties. The Sandcastle.Include file does the rest for you. You only have to set the right path names into the Sandcastle.include.

The example solution, including the NANT Project can be downloaded here: HelloSandcastle Example!

And for the completness, below you can find the code of the Sandcastle.Include file.

– Gerhard

kick it on

Annotation: The NANT process will end with a minor failure that I could not resolve. The HHC process always ends up with a 1 which leads to this error. But the CHM File will be created, so you can ignore the failure.

<?xml version="1.0"?>
<project name="Sandcastle" default="build" basedir=".">

  <!-- Directories  -->
  <property name="hhc.exe" overwrite="false"     value="D:\Programme\HTML Help Workshop\hhc.exe" />
  <property name="sandcastle.dir"                value="D:\Programme\Sandcastle" />
  <!-- Executables -->
  <property name="sandcastle.mrefbuilder.exe"    
     value="${sandcastle.dir}\productiontools\mrefbuilder.exe" />
  <property name="sandcastle.buildassembler.exe" 
     value="${sandcastle.dir}\productiontools\buildassembler.exe" />
  <property name="sandcastle.xsltransform.exe"   
     value="${sandcastle.dir}\productiontools\xsltransform.exe" />
  <property name="sandcastle.chmbuilder.exe"     
     value="${sandcastle.dir}\productiontools\chmbuilder.exe" />

  <!-- Directories -->
  <property name="sandcastle.workingdir" value="Sandcastle" />
  <property name="sandcastle.html.dir"   value="${sandcastle.workingdir}\Html" />
  <property name="sandcastle.chm.dir"    value="${sandcastle.workingdir}\Chm" />
  <property name="sandcastle.chm.file"   value="${solution.file}"/>

  <!-- Transformations -->
  <property name="sandcastle.addoverloads.xsl"          
     value="${sandcastle.dir}\ProductionTransforms\ApplyVsDocModel.xsl" />
  <property name="sandcastle.addfriendlyfilenames.xsl"  
     value="${sandcastle.dir}\ProductionTransforms\AddFriendlyFilenames.xsl" />
  <property name="sandcastle.reflectiontomanifest.xsl"  
     value="${sandcastle.dir}\ProductionTransforms\ReflectionToManifest.xsl" />
  <property name="sandcastle.createvstoc.xsl"           

    ******************************************************  -->
  <target name="Sandcastle.Doc">

    <!-- Check environment -->
    <fail if="${not file::exists(hhc.exe)}" 
     message ="HTML Help Workshop not found at ${hhc.exe}"/>
    <fail if="${not file::exists(sandcastle.mrefbuilder.exe)}" 
     message ="MRef Builder not found at ${sandcastle.mrefbuilder.exe}"/>
    <fail if="${not file::exists(sandcastle.buildassembler.exe)}" 
     message ="Build Assembler not found at ${sandcastle.buildassembler.exe}"/>
    <fail if="${not file::exists(sandcastle.xsltransform.exe)}" 
     message ="XSL Transform not found at ${sandcastle.xsltransform.exe}"/>
    <fail if="${not file::exists(sandcastle.chmbuilder.exe)}" 
     message ="CHM Builder not found at ${sandcastle.chmbuilder.exe}"/>

    <!-- Specifies the DLL file that we want to document -->
    <property name="sandcastle.input.files"       value="..\${solution.output}"/>

    <!-- Delete working directory -->
    <delete dir="${sandcastle.workingdir}"/>

    <!-- Copy configuration file, and hard code references -->
    <copy file="${sandcastle.dir}/Presentation/vs2005/Configuration/Sandcastle.config"
        <replacestring from="%DXROOT%" to="${sandcastle.dir}\" />
        <replacestring from=".\comments.xml" to="..\${solution.comments}" />
        <replacestring from=".\Output\html" to=".\Html"/>

    <!-- Create HTML Output Environment -->
    <mkdir dir="${sandcastle.html.dir}" />

    <!-- Create CHM Output Environment -->
    <mkdir dir="${sandcastle.chm.dir}" />
    <copy todir="${sandcastle.chm.dir}">
      <fileset basedir="${sandcastle.dir}/Presentation/vs2005">
        <include name="Scripts\*.*"/>
        <include name="Icons\*.*"/>
        <include name="Styles\*.*"/>

    <!-- Run MRefBuilder (introspection on assemblies) to create basic Reflection XML -->
    <exec program="${sandcastle.mrefbuilder.exe}" workingdir="${sandcastle.workingdir}">
      <arg value="${sandcastle.input.files}" />

      <!-- If you have dependencies 
      <arg value="/dep:&quot;D:\oracle\102\\bin\2.x\Oracle.DataAccess.dll&quot;"/>
      <arg value="/dep:&quot;C:\Program Files\Microsoft CE\v3.1\System.Data.SqlServerCe.dll&quot;"/>
      <arg value="/out:reflection.org1.xml" />

    <!-- Create final Reflection XML -->
    <!-- Regroup overloads -->
    <exec program="${sandcastle.xsltransform.exe}" workingdir="${sandcastle.workingdir}">
      <arg value="reflection.org1.xml" />
      <arg value="/xsl:&quot;${sandcastle.addoverloads.xsl}&quot;" />
      <arg value="/out:reflection.org2.xml" />

    <!-- Create filenames for html documents -->
    <exec program="${sandcastle.xsltransform.exe}" workingdir="${sandcastle.workingdir}">
      <arg value="reflection.org2.xml" />
      <arg value="/xsl:&quot;${sandcastle.addfriendlyfilenames.xsl}&quot;" />
      <arg value="/out:reflection.xml" />

    <!-- Create Manifest (list of Topics) -->
    <exec program="${sandcastle.xsltransform.exe}" workingdir="${sandcastle.workingdir}">
      <arg value="/xsl:&quot;${sandcastle.reflectiontomanifest.xsl}&quot;" />
      <arg value="reflection.xml" />
      <arg value="/out:manifest.xml" />

    <!-- Run BuildAssembler (create html topic files) -->
    <exec program="${sandcastle.buildassembler.exe}" workingdir="${sandcastle.workingdir}" >
      <arg value="manifest.xml" />
      <arg value="/config:Sandcastle.config" />

    <!-- Generate an intermediate Toc file that simulates the Whidbey TOC format. -->
    <exec program="${sandcastle.xsltransform.exe}" workingdir="${sandcastle.workingdir}">
      <arg value="/xsl:&quot;${sandcastle.createvstoc.xsl}&quot;" />
      <arg value="reflection.xml" />
      <arg value="/out:toc.xml" />

    <!-- Generate HHP File -->
    <exec program="${sandcastle.chmbuilder.exe}" workingdir="${sandcastle.workingdir}">
      <arg value="/project:${sandcastle.chm.file}" />
      <arg value="/html:Html" />
      <arg value="/lcid:1033" />
      <arg value="/toc:toc.xml" />
      <arg value="/out:Chm" />

    <!-- Generate CHM file -->
    <exec program="${hhc.exe}"

6 Responses to “How to build CHM / HTML Documentation with Sandcastle September CTP 2007 and NANT”

  1. CowDir Says:

    Pretty awesome article. Thanks! – CowDir

  2. Brett Says:

    Do you store all the artifacts in source control, including the .exe’s?

  3. Gerhard Stephan Says:

    Hi Brett,

    no – I only store source code within source control. Documentation files are stored within SharePoint and Executables (each per version) on a fileshare.

    Why do you ask?

  4. roshanjain123 Says:

    good one…

  5. Brett Says:

    I wondered because when MSFT sends out a new CTP or version, the exe’s, XSL’s, etc may change. I wondered if you just installed over your current version and then updated your script or had previous versions available for rollback.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s


Get every new post delivered to your Inbox.

Join 108 other followers

%d bloggers like this: