Creating Build Process Plug-Ins
This topic will walk you through the creation of a plug-in project.
The first step is to determine what items will appear in the plug-in configuration. The configuration is stored as an XML fragment in the help file builder project file. The root node is always configuration. Define your own elements to contain the plug-in configuration that will be nested within the root element. When first added to a project, the configuration will be empty. Your plug-in should use appropriate default values as needed. It is possible that a plug-in will have no configurable elements. In that case, there is nothing to add to the default configuration. Below is an example of a configuration that is passed to a plug-in.
<configuration> <ajaxDoc url="http://localhost:/AjaxDoc/" project="MicrosoftAjax" regenerate="true" /> <userCredentials useDefault="true" userName="" password="" /> <proxyCredentials useProxy="false" proxyServer=""> <userCredentials useDefault="true" userName="" password="" /> </proxyCredentials> </configuration>
This section describes how to create and configure the build process plug-in project. It will describe the process for a C# project but the steps should be fairly similar for a VB.NET project with a few differences in the configuration option titles.
In Visual Studio, select the New Project option. In the New Project dialog box, select the C# or VB.NET language, and then select the Documentation subcategory. Select the Sandcastle Help File Builder Plug-In template, give it a name and click OK to create it. Once it has been created, right click on the project and select Properties.
In the Application tab, set the assembly name and default namespace as you see fit.
On the Debug tab, set the Start Action to "Start external program" and enter the path to the SandcastleBuilderGUI.exe program. If you installed the help file builder in the default location, this will be %ProgramFiles(x86)%\EWSoftware\Sandcastle Help File Builder\. If not, substitute your path as appropriate.
Using the standalone GUI as the host is easier than using Visual Studio as the package locks the assemblies once the help file builder project has loaded them for use and you will not be able to rebuild them. Shutting down the standalone GUI frees the assemblies so that you can rebuild them and start a new debugging session.
In the help file builder project that you use to test your plug-in, set the project's Component Path property to the folder containing your plug-in's assembly. If you have opened the project's Plug-Ins property page before setting the component path, you may need to close and reopen the project in order for it to discover your plug-in assembly.
Optionally, select the Signing tab and check the "Sign the assembly" checkbox. Select "<New...>" from the "Choose a strong name key file" dropdown, enter a filename, and click OK to create the key file. You can protect the key file with a password if you like or uncheck the option to create one without a password.
You are now ready to edit the plug-in class itself. See the comments in the template class for information on how to get started. Some general information is given below. Note that multiple plug-ins can reside within the same assembly. Add new class files to the project and implement the necessary methods as described below and as shown in the template class.
The plug-in is derived from the SandcastleBuilder.Utils.BuildComponentIPlugIn interface and consists of a few properties and methods that you must implement. These are described below. Review the code for "TODO:" comments to find sections that need attention such as setting the plug-in's ID, defining the execution points, etc. If you followed the steps in the Creating the Project section, you can run the project and debug it by setting breakpoints in the plug-in's code. As noted above, set the test project's Component Path property to the folder containing the plug-in assembly first. If necessary, close and reopen the test project so that it can discover the plug-in.
The plug-in is a Managed Extensibility Framework (MEF) component. The HelpFileBuilderPlugInExportAttribute is used to define the necessary metadata that enables the help file builder to load and use the component.
The Id parameter is required and is used to uniquely identify the plug-in.
The Version property is optional and allows you to define the plug-in version displayed in the help file builder property page when the plug-in is selected.
The Copyright property is optional and allows you to define the plug-in copyright displayed in the help file builder property page when the plug-in is selected.
The Description property is optional and allows you to define the plug-in description displayed in the help file builder property page when the plug-in is selected.
The RunsInPartialBuild property is optional and allows you to define whether or not the plug-in runs during a partial build. Partial builds occur when generating the reflection data for the namespace comments and API filter editor dialogs. In such cases, the plug-in may not be needed. If this property returns false, the default, the plug-in is omitted which can speed up the partial build. Set it to true if your plug-in adds information needed for the reflection data or namespace comments.
The IsConfigurable property is optional and allows you to define whether or not the plug-in supports interactive editing of its configuration. If false, the default, the plug-in will not be configurable from the property page. If true, the property page will call the ConfigurePlugIn method so that it can invoke a dialog box to edit the configuration.
The IsHidden property is optional and allows you to define whether or not the plug-in is hidden and does not appear on the project property page. If false, the default, the plug-in will appear on the property page. If true, the property page will not list it as one that can be added to the project. This is useful for presentation style dependency plug-ins that have no configurable elements and thus do not need to be manually added to the project to override settings.
The interface consists of one property and four methods.
The ExecutionPoints property is probably the most important member of the interface. It returns a collection of ExecutionPoint objects that define at which steps in the build process the plug-in should be ran. Execution points can be set to run before and/or after a build step to supplement the default processing or they can be set to run instead of the build step to completely suppress or replace the default processing. See the BuildStep enumeration for a list of the defined build steps.
Each execution point can be assigned a priority. The execution priority is used to determine the order in which the plug-ins will be executed. Those with a higher priority value will be executed before those with a lower value. Those with an identical priority may be executed in any order within their group. If not specified, a default priority of 1,000 is used.
The ConfigurePlugIn method is used to configure the plug-in interactively from within the help file builder. The method is passed a string containing the XML fragment that defines the current configuration. It should return a copy of the edited configuration.
The Initialize method is used to initialize the plug-in at the start of the build process. It is passed a reference to the current BuildProcess and an XPath navigator containing the plug-in configuration. You should cache a copy of the build process reference for use during execution as it contains many properties and methods that you will find useful.
The Execute method is called to perform the plug-in processing during the relevant build steps. It is passed an SandcastleBuilder.Utils.BuildComponentExecutionContext object that defines the current execution context. If your plug-in determines that it does not need to run, it should set the ExecutionContextExecuted property to false. This is especially important for plug-ins with the InsteadOf behavior. If none run, the default processing will occur.
The Dispose method can be used to dispose of any resources used during the build process. If you do not have any resources that need to be disposed of, this method can be left as it is and the finalizer method can be removed.
There are certain conditions to be aware of when choosing and coding the execution behavior for your plug-in.
The earliest execution point for a plug-in is the After behavior with the Initializing step.
The Before behavior cannot be used with the Initializing, Canceled, or Failed steps.
The InsteadOf behavior cannot be used with the Initializing, Completed, Canceled, or Failed steps.
The InsteadOf behavior always takes precedence. The build process will not call any plug-ins with Before or After behavior for the step if an InsteadOf plug-in runs. As such, it is up to the plug-in with the InsteadOf behavior to call the ExecuteBeforeStepPlugIns and ExecuteAfterStepPlugIns methods to run them if needed.
If the build step involves creating, modifying, or deleting a non-script file or folder, the Before behavior is always executed prior to creating/modifying/deleting the file or folder. Use the After behavior if you need to guarantee that the file or folder exists or you do not want your version overwritten. The exceptions to this rule are MSBuild project files (*.proj) and MRefBuilder.config which are always created prior to running the Before behavior plug-ins. This allows you to modify the script files prior to them being ran.
If the build step involves creating, modifying, or deleting a script file or folder and the InsteadOf behavior is used, the plug-in is responsible for creating the script file/folder. All normal processing involving the file/folder including its creation is skipped.
The GenerateHelpFormatTableOfContents, GenerateHelpFileIndex, GenerateHelpProject, UpdateTableOfContents, and CompilingHelpFile steps will run once for each help file format selected. You can use the CurrentFormat property to determine the current help file format being built in order to skip or alter the plug-in's processing based on the help file format.
Be aware that the HTML Help 1 index and table of contents files and the website table of contents file are actually generated as part of the ExtractHtmlInfo step. However, the before and after plug-in behaviors for the index and table of contents steps in each of those formats will still be executed.