Monday, July 16, 2007

Context Help Made Easy - Revisited

Some time ago I've read a great article Context Help Made Easy by Tom Clement. The article can be found here.

Tom's idea is great - rather than putting the HelpProvider on each of your application's forms, you keep the information about the topic mapping in a single XML file. There is also an additional message filter executing in the application context which traps F1 presses, reads the provided topic mapping and redirects the help provider to the specific topic.

The most interesing part of Tom's article is the idea of instrumenting the execution and providing a dialog form which is used to provide topic mapping for current context. It is then possible to train someone to use this feature to map user interface contexts to help topics - the mapping is provided while the application is actually running and not in the design time.

Below is the brief description of differences between Tom's and my implementation.

  • in Tom's implementation the Main routine of the application has to be augmented with the message filter injection. In my implementation - a custom component is used so that the only thing you have to do is to put the component on the main form of the appliaction
  • in Tom's implementation all user interface controls have to implement the mapping interface. I belive that this is not necessary - help topics can be mapped to a context defined by the FormClassName/Control1Name/Control2Name/Control3Name/..../ControlNName built directly from the runtime information (parent-child relation of controls and controls' names)
  • From the point of view of someone who actually maps controls to help topics the hierarchical view is much more natural than the flat ListView. In my implementation, topics which are not mapped are shown as red and topics already mapped - as black (please forgive localized labels, feel free to customize it)

  • in my implementation the XML file used to store the topic mapping, help.mapping, can be stored as a resource in any application module. If the file is found in the same directory as the main executable file of the application - it is used as a primary source of the topic mapping.
  • in Tom's implementation the ability to provide topic mapping is available always by pressing Ctrl+F1 instead of F1 which just shows the help topic. In my implementation you have to provide a special runtime commandline parameter, helpbuilder, to be able to use the map builder
  • the Control.FromHandle method used by Tom to retrieve the control instance from the window handle does not always work as expected. For example - when a ComboBox in DropDown mode is active then the message filter gets not the handle of the combo but rather the handle of the combo's internal textbox. The Control.FromHandle does not work then because the combo's internal textbox is not a control instantiated by the .NET. In my implementation when Control.FromHandle fails, the application tries to retrieve the control's parent control and repeats the Control.FromHandle. This correctly resolves the ComboBox (and other composite controls) issue.

In order to make your application compatible with my library you have to:

  • recompile the library from the provided source
  • put the HelpComponent on the main form of your application
  • run the application with helpprovider commandline parameter
  • use Ctrl+F1 to map help topics to controls. Remember about the hierarchy - you do not have to provide topics for all controls, it is sufficient to provide the topic for a container control and all its child controls inherit the mapping.
  • remember to provide a help file name (must be a *.chm file located beside the application main executable)
  • when the mapping is complete, include the help.mapping file stored beside the application main executable as an embedded resource in one of assemblies
  • remove the help.mapping file located beside the application main executable
  • rebuild the application

From now, the included resource is used as a primary help mapping provider. If you need to customize it further, repeat above process starting with the 3rd step (the included resource will be copied as a file beside the application main executable and used as a primary help mapping provider.

Download the source code here. You are free to use and modify it without any explicit permission.

Please leave a comment if you find this small library usable.

Edit: Please also take a look at the second part of this article:


Tom Clement said...

Wiktor, thanks for making these improvements. I like them and agree with your ideas. It would be great if you added a comment to the CodeProject article that points users to this blog so others could benefit from your ideas.

Wiktor Zychla said...

Tom, thank your great idea. I will add a comment under your article on CodeProject.

Unknown said...

Hi Tom, when i am passing helpprovider as commandline argument and running the application nothing is heppening so plz help me out

Unknown said...

i am giving helpprovider as commandline argument but when pressing cntrl+F1 then it is showing filenotfound exception plz tell me the steps and how to do it

Unknown said...

in step3 command line argument should be "helpbuilder" instead of "helpprovider".


Anonymous said...

Is this supposed to show an entire hierarchy of every control in a project?

All I get is a couple of components on the main form. Other forms don't appear at all. Even the screen shot in your blog only has a few components on it.

Sorry, but I can't see how this is useful unless all the controls in a solution/compiled .exe are exposed for mapping.

Robert W. said...


I was just introduced to your blog by a Russian colleague of mine who lives near me here in Vancouver, BC, Canada. Great stuff!

Robert Werner

P.S. I love how the Internet has made our planet earth a very small world!

Wiktor Zychla said...

nm - no, it is not supposed to show the entire hierarchy! it is supposed to show the current hierarchy, determined by the active control on which you press the Ctrl+F1.

then you press the ctrl+f1 on another control, provide the topic mapping and repeat the process for all other controls.

Hem Chandra Padhalni said...

Wiktor does this library suppose to work for multiple .chm files, I have Modular help system where there is one master chm file and lots of slave chm files, now I want to map the context id's residing in different .chm files, i tried to do that, however it overwrites the eariler entries in mapping file

Wiktor Zychla said...

it should be easy to extend the definition of the help item to store also the name of the .chm file and then use this information to open the topic entry from the given file. just take a look into the sources I've provided and you should not have any major problems.

Geert van Horrik said...

Great work, I have slightly modified the editor so it automatically selects the available help files and shows them in a combobox (easier for the editor). I also implemented a new constant that allows a developer to determine the path of the help file (for example, I want the help files to be located in a subfolder called Help).

However, the most important fix is to make the files load in read-only mode. In your code, it requires elevation on Vista because you request write rights. This is fine when I am an editor (and I trust the application), but not for a regular user.

Anyway, thanks for these great improvements! This makes implementing a help system actually fun!

Wiktor Zychla said...

thanks for the note.

could you publish your changes somewhere and put the link here and below Tom's original article so that others could also make use of your improvements?

Geert van Horrik said...

You can find the updated source at my blog:

Anonymous said...

You just saved me a LOT of work. Than you very much. It works great!


Anonymous said...

This looks gr8... I have some issue tho...Whe I delete the maping fil from the location where exe exists after embedding as a resource, F1 doesn't work. But on Ctrl+F1 does work...again I need to enter proper html file names etc. Point is after editor sets the files as help, how do we restrict this from end user editing it again (Ctrl+F1)


Wiktor Zychla said...

I guess you do something wrong as I've never had any issues you mention. Note, that to edit help topics the application has to be invoked in a special way (the runtime parameter in my case but you can use any other restriction like an expected value in a registry key) so that the probability of a user invoking the application in help-editing mode is rather low.

Anonymous said...

Who knows where to download XRumer 5.0 Palladium?
Help, please. All recommend this program to effectively advertise on the Internet, this is the best program!

Anonymous said...


I just wanna thank you for this library.

It saved me a lot of work.

Best Regards,

João - Portugal

Ashish Kumar said...

Great article!

By the way, have you run into HelpProvider issue with TabPage control. A context sensitive help at TabPage level does not work one of the controls within that tab does not have the focus. In other words, if the focus is just on the Tab's label and you press F1, any context sensitive nature of that Tab will not work. The help, which will come up will be what you defined at the form level.

Pramod said...

I m try to open HelpEditor using Ctrl + F1 but i not able to open.

Please help me how I can do that.


Wiktor Zychla said...


you have to run your application with the "helpbuilder" commandline argument:

myapp.exe /helpbuilder


Pramod said...

I run the application using the command line argument. But still it is not showing editor window.

Do i need to do changes in Catenalogic.Help dll


Anonymous said...

Any chance there is anything like this for WPF that allows such easy mapping?

Robr said...

Wiktor, like the idea but cant get the mapping to work..

I have setup mapping to a Topic but when press F1, it loads the chm but doesnt go direct to the topic. shows "cannot display webpage"

is there a sample working mapping file available ?

Do I have to follow the when I