FAQ‎ > ‎

API, F1, URLs & Code

A quick introduction to the world of the Help Viewer 1.0 API.
DisplayTopicFromId()
DisplayTopicFromURL()
DisplayTopicFromF1Keyword()

The following methods are no longer supported in VS 2010:

DisplayTopicFromURLEx()
DisplayTopicFromKeyword()
DisplayTopicFrom_OLD_Help()
DisplayTopicFromURLEx2()

Of course these all work on the VS\100\* help catalog. You would need to roll your own (see below) to access help from other catalogs. Paul also has a code example showing how to implement these API calls.

Where is the API?

Normally we think of an "Application Programmer Interface" as a set of functions our program can call (via COM or DLL interface etc) to access some technology. 

MS Help Viewer is a little unusual in that we send Help API commands and parameters embedded in a URL. The "Help Library Agent" application is listening on HTTP localhost port 47873 (port 80 for the Beta) looking for http://127.0.0.1:47873/help/1-xxxx/ms/help/? type pattern. If it finds this URL it unpacks the parameters and returns the requested topic or data in HTML or XML format. This is why Help Viewer 1.x works with any browser. 

BTW the name for this style of communication is REST (see Wikipedia REST reference).

A new help protocol ms-xhelp:/// is associated with the HelpLibAgent.exe application.

ms-xhelp:///?name=value&name=value&...

Agent reads this URL and converts it to a local http://127.0.0.1/ URL that browsers can understand. 

http://127.0.0.1:<port>/help/<session>-<agentProcessId>/ms.help?name=value&name=value&...


So Help Viewer 1.0 installs the ms-xhelp:/// protocol and associates this protocol with the Help Library Agent application. It takes the same parameters as the http:/// URL. The only application that understands this protocol is the Agent application (oh and also our H3Viewer application). ShellExecute() a ms-xhelp://... URL and Agent will startup and send the results to the default browser. This is what VS 2010 F1 help uses.

ms-xhelp:///?name=value&name=value&...


Once you start working with this new style API you realize it is extremely fast and flexible. Agent is a .NET application so there is a slight delay when it first starts up, loading the .NET framework into memory. After that it takes under a second to retrieve data from a million topic catalog. As an example I built a full Help Viewer (with full TOC and Index, and search) in about a week (see H3Viewer.exe). IMHO this is the best Help API MS have ever delivered. The system shows great potential.

HelpLibAgent runs as a tray application. Right click to exit the application. It will restart next time a ms-xhelp:/// URL is executed. 


The Help Library Agent application running in the notification area of the taskbar

Online Vs Offline Mode

Once Agent is running you can use the http:///127.0.0.1/.. type URL. Unfortunately for this first release Agent wont start up if VS is in Online mode (which is the default). Although a valid ms-xhelp:/// F1 call to a local help topic will always start agent. In Local (Offline) mode you can silently start agent simply by running HelpLibAgent.exe.

Thus applications such as H3Viewer and bookmarks that need to access offline content wont work in Online mode. You will need to prompt the user to change to Local (Offline) mode. This limitation should be addressed in a future release.

Note: To flip between Online and Offline mode run Help Library Manager.

Which Protocol?

Http is very flexible. Most programmers know how to open a URL and capture the response as a stream, string or file. And most programmers know how to embed the IE browser control in an application and send it to a URL. The only catch with http:/// Help URLs is that the Agent application must be running to open a help topic. So if you have an application that calls Help either run HelpLibAgent.exe just prior to making the call (it wont hurt if Agent is already running). Or use the ms-xhelp:/// protocol.

So http:/// is very good for programmer type stuff, while ms-xhelp:/// is a reliable way to show F1 help and open search in the default viewer\browser (this is what VS 2010 F1 help uses).
  • http://127.0.0.1:<port>/help/<session>-<agentProcessId>/ms.help?... name=value pairs
    • URL will open in a browser or anywhere a normal http:/// URL will open.
    • Programmer can capture the response in a string, stream or file. Or send to a browser.
    • HelpLibAgent.exe must be running or the URL wont open. An application must run Agent beforehand.
    • Programmer must do some extra work to find the current localhost port, session number and Agent process Id.

  • ms-xhelp:///?... name=value pairs
    • Runs via ShellExec() type call. Only Agent EXE understands this protocol.
    • Response is always sent to the default viewer\browser. Although this can be configured (see "overriding default browser" below)
    • HelpLibAgent.exe will startup in response to running this URL.
    • Simple URL. It just works.
Both URLs contain the same name=value pairs after the ? character. In the future there maybe other types of URLs for accessing help on local servers etc.

Notice that when you run an ms-xhelp:/// help url Agent turns it into a http:/// help URL so it can open in the default browser.


URL Format

Here is an example of an F1 call:

ms-xhelp:///?method=f1&query=100&format=html&product=VS&productVersion=100&locale=en-us

So here (above) we are using the ms-xhelp:/// protocol. After the ? comes a number of name=value pairs separated by the & char (order and case are not important). Use "method=XX" to specify the type of API command. The f1 command requires "query=SomeContextID" to specify the context ID. The response is formated as HTML but you can also specify "format=xml" for some API commands and you will get a response without the branding information.

Finally you must always specify the catalog to use: "product=VS&productVersion=100&locale=en-us" (although most API commands allow you to drop the locale parameter). VS\100\en-us is of course the help catalog that ships with English VS 2010.

API Commands

To explore the various API commands download mshcMigrate.exe (build 31 or later). 
On the Help Library Agent page you can play with the various parameters. There are currently 8 API commands that I know of: 
  1. Page - Supply the topic Help ID and open that topic.
  2. Keywords - Perform a K-Index keyword query.
  3. F1 -  Perform an F1-Index keyword query.
  4. Search - Perform a search query.
  5. TOC - Given a topic Help ID returns TOC Parents, Siblings, Children (similar to the LoBand TOC that MSDN uses)
  6. Ancestors - Returns TOC parents right up to the root.
  7. Children - Returns list of TOC children.
  8. Path - Using an absolute path, open any file in any package in the help library store.
Read the mshcMigrate SuperTips for deeper information. There is also some API notes here: http://www.helpware.net/mshelp3/intro.htm#Links


mshcMigrate > Help Library Agent page - Explore the Help API calls

F1 Command

ms-xhelp:///?method=f1&query=100&format=html&product=VS&productVersion=100&locale=en-us

In the above F1 example we have a problem. An help context Id of "100" is not unique.

The F1 command has no disambiguation. Agent will perform a non-case sensitive search and display the first match it finds ignoring all the rest. Your help topic may be merged with a million other topics in the VS\100\* catalog so help context ids like "100" have little chance of being unique. 

There is a solution. The F1 command can also take a category parameter. So for example you could stamp all topics in your help package with 

<meta name="Microsoft.Help.Category" content="company.product.id">
 
Don't forget to add your F1 context ids to your topics too. You can add several F1 tags to each file. But make sure each file has unique IDs within your category.

<meta name="Microsoft.Help.F1" content="100" />
<meta name="Microsoft.Help.F1" content="ColorParamCall" />

Once you have recompiled your help, you can now use the category parameter in your API calls.
ms-xhelp:///?method=f1&query=100&format=html&category=company.product.id&product=VS&productVersion=100&locale=en-us

That's about it calling F1 help from your own application. If you wanted to test whether an F1 topic was installed from your application, you could use the http:/// protocol and do a silent test by capturing the result. If the resulting page is a 404 topic then you know the F1 topic is not installed.

As far as F1 Help within VS 2010 IDE goes... It looks like if your help topic has an F1 keyword = the full expanded class name, then F1 should just work. Most component makers will use Sandcastle which automatically turns your embedded code comments into a Help 3 package.

Programming Notes

Calling the API with the ms-xhelp:/// Protocol

Running a ms-xhelp:/// URL is very simple. In case you forgot here's how we do it in C#.

// Simplest way to open a URL in C#
System.Diagnostics.Process.Start("ms-xhelp://?...");

Here is how we run it in win32 (Delphi).

sFilename = 'ms-xhelp://?...
sParams = '';
iRet := ShellExecute(handle, 'open', PChar(sFilename), PChar(sParams), nil, SW_SHOWDEFAULT);
if (result <= 32) then
  Show Error message

Calling the API with the http:/// Protocol

Paul O'Rear passed on this C# example of how to capture the response from an http:/// API call using C#.

    // Get Help XML as a string
    public static string GetHelpXmlAsString(string helpUrl)
    {
        string returnXml = "";
 
        Stream webStream = GetHelpXmlAsStream(helpUrl);
        StreamReader webReader = new StreamReader(webStream);  
        string sLine = "";
        while (sLine != null)
        {
            sLine = webReader.ReadLine();
            if (sLine != null)
                returnXml += sLine;
        }
 
        webStream.Close();
 
        return returnXml;
    }

 For win32 code I use WinINet calls to capture the http response.

Finding the HTTP Session ID

http://127.0.0.1:<port>/help/<session-id>-<process-id>/ms.help?

The session ID is usually 1 on standalone PC (although I saw it as 2 once). Agent makes sure that every user has a unique session ID. If two people are logged into a terminal services box, they would have different session numbers.


Required references:
 
using System;
using System.IO;
using System.Net;
using System.Xml;
using System.Runtime.InteropServices;
 
Native interop code:
 
    [DllImport("Wtsapi32.dll")]
    internal static extern bool WTSQuerySessionInformation(System.IntPtr hServer, int sessionId, WTSInfoClass wtsInfoClass, out System.IntPtr ppBuffer, out uint pBytesReturned);  
    [DllImport("wtsapi32.dll", ExactSpelling = true, SetLastError = false)]
    public static extern void WTSFreeMemory(IntPtr memory);  
    internal enum WTSInfoClass
    {
        WTSInitialProgram,
        WTSApplicationName,
        WTSWorkingDirectory,
        WTSOEMId,
        WTSSessionId,
        WTSUserName,
        WTSWinStationName,
        WTSDomainName,
        WTSConnectState,
        WTSClientBuildNumber,
        WTSClientName,
        WTSClientDirectory,
        WTSClientProductId,
        WTSClientHardwareId,
        WTSClientAddress,
        WTSClientDisplay,
        WTSClientProtocolType
    }
 
    internal static IntPtr WTS_CURRENT_SERVER_HANDLE = IntPtr.Zero;
    internal static int WTS_CURRENT_SESSION = -1;  
 
Functions to get XML back from help:
 
    internal static int GetSessionNumber()
    {
        IntPtr pSessionId = IntPtr.Zero;
        Int32 sessionId = 0;
        uint bytesReturned;
 
        try
        {
            bool retVal = WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE,
              WTS_CURRENT_SESSION, WTSInfoClass.WTSSessionId, out pSessionId, out bytesReturned);
            if (retVal)
                sessionId = Marshal.ReadInt32(pSessionId);
        }
        finally
        {
            if (pSessionId != IntPtr.Zero)
                WTSFreeMemory(pSessionId);
        }
 
        return sessionId;
    }



Finding the Agent Process ID

http://127.0.0.1:<port>/help/<session-id>-<process-id>/ms.help?

The Agent process Id will obviously change ever time HelpLibAgent.exe is restarted.
This code get all instances of Agent running on the local computer. If you get any processes back then you know Agent is running and the Id is a property of Process.


Process [] agentProcess = Process.GetProcessesByName("HelpLibAgent");

If Agent is not running, you can simply run HelpLibAgent.exe


System.Diagnostics.Process.Start(pathToHelpLibAgent);


Finding the HTTP Port

http://127.0.0.1:<port>/

The default port for the release build is port 47873.
If a different port is used then it will be available at the following registry location.

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Help\v1.0
AgentPort="port-number"


Hiding the Embedded Navigation Pane in a Topic


You will notice that in offline help each topic has an embedded navigation pane (Search box + Loband style TOC).
H3Viewer usually hides this by injecting JavaScript (See the Navigation button). In Help Viewer RC + RTM release you can now hide this embedded navigation by adding "&embedded=true" to the offline URL.

So this URL wont display a navigation

http://127.0.0.1:47873/help/1-1600/ms.help?method=f1&query=system.string&product=vs&productversion=100&locale=en-us&embedded=true

March 2011 - Help Viewer 1.1

For Help Viewer 1.1 things are slightly different. The new dedicated help viewer with it's own tradition TOC and hides the embedded TOC by default. You can still show the embedded TOC by appending &embedded=false to the URL.

Overriding Agents Default Viewer

This registry setting allows you to override the default application run by Agent. So instead of opening the result in the default browser you could specify another browser (if you know the full path to the browser EXE) or a 3rd party viewer such as H3Viewer.exe. Note that VS 2010 uses the ms-xhelp:/// protocol to open its F1 help, so this would also change the VS default help viewer.

See also blog post: Overriding the Default Viewer

Example 1: Set H3Viewer as the default viewer

HKLM\Software\Microsoft\Help\v1.0
HelpViewerProgID=c:\program files\Helpware\H3Viewer\H3Viewer.exe

Example 2: Set Google Chrome as the default viewer

HKLM\Software\Microsoft\Help\v1.0
HelpViewerProgID=c:\Users\Robert\AppData\local\Google\Chrome\Application\chrome.exe

Summing up

That's a very quick introduction to using the new Help API. Hopefully it fills in some blanks.

Contact me if you need more info. Ask me directly or post in the MSHelpViewer Yahoo discussion group.
Thanks Paul O'Rear [MS] for your guidance and enormous patients. Paul is also a member of the MSHelpViewer discussion group.

September 2010 - Microsoft have released a Help Viewer 1.x SDK containing documentation and code fragments:

Comments