Creating a .NET based Add-In

A .NET add-in is specified by providing a path to the assembly for the add-in, a type to instantiate, and a method to call. The method must accept a single object parameter that is the Help Builder IDE form as a reference.

The easiest way to create a Help Builder add-in is to create a new project and a reference to wwReflection.dll in the Help Builder main directory. wwReflection contains a wrapper type for the Help Builder COM object so you get strong typing for the Help Builder IDE instance. Without this wrapper the COM object returned will be accessible only via Reflection.

Ok, let's see this work. Create a new project in VS.NET. I'm going to create it in a directory below the add-ins directory called HelpBuilder_Addin.

The first thing I'll do is to add a reference to wwReflection20.dll from the <HelpBuilderInstallFolder>\bin\wwReflection20.dll):

Once added to the project, you can set the Copy Local flag to false because wwReflection20.dll will already be loaded - the Add-in Mechanism always calls through this assembly anyway, so there's no reason to copy it twice. Click Properties on the assembly and change the flag.

Ok, now you're ready to create your add-in code. Create a source file for the Add-in and call it SampleAddin.cs (or equivalent VB.NET).

using System;
using System.Windows.Forms;

using Westwind.wwHelp;

namespace HelpBuilder_Addin
{
/// <summary>
/// Summary description for SampleAddin.
/// </summary>
public class SampleAddin
{
	public bool Activate(wwHelpForm HelpForm) 
	{
		MessageBox.Show("Made it into .NET." + DateTime.Now.ToString());
		
		if (MessageBox.Show( HelpForm.Help.Topic.Topic + "\r\n"  +
				    HelpForm.Help.Topic.Body + "\r\n\r\n" + 
                    "The next step is going to change the body of the active topic\r\n" +
                    "by inserting the DateTime at the top of the topic.\r\n\r\n" +
                    "Do you want to continue","Add-in Test",
			        MessageBoxButtons.YesNo,MessageBoxIcon.Question) == DialogResult.No)
			return true;  // *** Done - Success result
		
		// *** Demonstrate objects
		wwHelp Help = HelpForm.Help;             // wwHelp Project object
		wwHelpTopic Topic = HelpForm.Help.Topic; // Current Topic

		// *** Let's update the topic text
		Topic.Body = DateTime.Now.ToString() + "\r\n" + Topic.Body;
		HelpForm.Help.SaveTopic();

		// *** Refresh the topic display
		HelpForm.GoTopic();   

		return true;
	}
}
}

Note you have to include the Westwind.wwHelp namespace which contains the Help Builder wrapper objects. Any add-in method gets passed a wwHelpForm instance which is the Help Builder main form. From there you can get a reference to the underlying wwHelp engine itself with HelpForm.Help.

Note that you can bring up your own UI and even start up your own forms. For example to launch a form you can simply do:

TestForm testForm = new TestForm();
testForm.Show();
Application.Run(testForm);

as part of your add-in code. However, keep in mind that Help Builder will shut down the add-in after it has been executed so

Copy the code above just for testing and make sure it compiles. Next you have to register the add-in with Help Builder. In the Add-in manager pick the DLL:

  • d:\installs\wwhelp\addins\helpbuilder_addin\bin\debug\helpbuilder_addin.dll
  • Class Name: HelpBuilder_Addin.SampleAddin
  • Method: Activate

Note the classname will be fully qualified .NET classname or namespace + classname. Typically the method for an add-in is Activate, but you can choose any method as long as it has the same signature as the method above. The idea is that you can create more than one add-in method in a single class/assembly although each one has to be registered seperately.

Once you have added add-in click the Test button to fire the add-in. If all went well the add-in should fire up and you should see some message boxes and see the current topic changed with the time injected at the top.

Debugging your code

You can debug your code easily with Visual Studio .NET by setting up your debugger to start the Help Builder Executable. In your project options for the add-in project:

  • Make sure your project is set to Debug mode
  • Bring up the Project Properties
  • Configuration Propertiers | Debugging
  • Set the Start Application to wwHelp.exe
  • Set the startup directory to the Help Builder directory

Now set a breakpoint in the first line of the add-in code and run the project. Help Builder starts up. Go to the Add-in drop down and select your add-in and run it.

The debugger stops on your line of code.

Piece of cake. You're on your way to building an add-in for Help Builder.

A more advanced Example

The following is an example of a slightly more advanced add-in that parses through the items in the help file by using GetTopics. GetTopics returns a DataRowCollection of rows that you can loop through to either directly retrieve data or - more commonly - get a list of all PKs and then load up each topic as an object that you can directly manipulate and update.

This add-in is actually something I threw together quickly to fix up some compatibility issues between various Help Builder versions as it fixes up some remnants from older versions cleaning up various settings and field values.

using System;
using System.Collections.Generic;
using System.Text;
using Westwind.wwHelp;
using System.Windows.Forms;
using System.Data;
using System.Threading;

namespace HelpBuilder.Addins
{
    public class FixStatic_Addin 
    {
        public bool Activate(wwHelpForm HelpForm)
        {
            // *** Display a status progress window
            HelpForm.StatusType = StatusTypes.ProgressBar;

            HelpForm.StatusMessage("Initializing...","",0,"Updating Static Flag");            
            
            wwHelp Help = HelpForm.Help;

            // *** Retrieve a list of topics filtered by any type that starts with "CLASS"
            DataRowCollection rows = Help.GetTopics("pk,type,topic,syntax,static,inh_tree", "type='CLASS'","");

            int Counter = 0;
            int UpdateCount=0;
            foreach (DataRow row in rows)
            {
                Counter++;

                string Pk = (string)row["Pk"];
                string Syntax = (string)row["Syntax"];
                bool Static = (bool)row["Static"];
                string Topic = (string)row["Topic"];
                string InheritanceTree = (string)row["Inh_Tree"];

                bool Updated = false;

                if (!Static && 
                    Syntax.IndexOf(" static ", StringComparison.OrdinalIgnoreCase) > -1 ||
                    Syntax.IndexOf(" shared ", StringComparison.OrdinalIgnoreCase) > -1)
                {
                    // *** Load the topic, change value and save it
                    Help.LoadTopic(Pk);
                    Help.Topic.Static = true;
                    Help.SaveTopic();
                    Updated = true;
                }
                
                // *** Fix up the Inh_Tree of old syntax junk
                if (!string.IsNullOrEmpty("Inh_Tree"))
                {
                    string UpdatedTree = InheritanceTree.Replace("<br>", "").Replace("<b>", "").Replace("</b>", "").Replace(" ", "");
                    if (UpdatedTree != InheritanceTree)
                    {
                        // *** Load the topic, change value and save it
                        Help.LoadTopic(Pk);
                        Help.Topic.Inh_Tree = UpdatedTree;
                        Help.SaveTopic();
                        Updated= true;
                    }
                }

                if (Updated)
                    UpdateCount++;

                // *** Update the status message and progress bar
                int Perc = Convert.ToInt32(Convert.ToDecimal(Counter) / Convert.ToDecimal(rows.Count) * 100);
                HelpForm.StatusMessage("Checking " + Topic + " ", null,  
                                       Perc,
                                       null);
                
                // *** Give the UI some time to breathe
                Thread.Sleep(5); 
            }
            
            // *** Close the message display dialog and reset status bar message mode
            HelpForm.StatusMessage("CLEAR");
            HelpForm.StatusType = StatusTypes.StatusBar;

            // *** Display completion message
            string Message = "";
            if (UpdateCount > 0)
                Message = UpdateCount.ToString() + " static member topics have been updated.";
            else
                Message = "There were no static members to update.";

            MessageBox.Show(Message, "Fix Static Members", MessageBoxButtons.OK, MessageBoxIcon.Information);

            return true;
        }

    }
}

© West Wind Techologies, 2018 • Updated: 08/12/15
Comment or report problem with topic