Documentation‎ > ‎

HV2 API Calls

This page documents the MS Help Viewer 2.0 API calls. Eventually there will be official Microsoft documentation available but until then I hope this ties you over.

VS 11 Executables

Visual Studio 11 has 2x Help DLLs with COM interfaces. If you code in MS Visual Studio C#, right-click your project's "References" folder and select "Add Reference" and added the run-time DLL. The other DLL is only required if you need to accurately render MSDN documentation.

Location:  C:\Program Files\Microsoft Help Viewer\v2.0\
  • Microsoft.VisualStudio.Help.Runtime.dll -- Core help API. Open catalogs and read catalog data.
  • Microsoft.VisualStudio.Help.dll -- Render raw topics read from .mshc help files.

Windows 8 Executable

The WIndows 8 help API has the same interface as the VS runtime API. Useful for targeting machines without VS 11.
To use the Win 8 API instead of the VS Help API (coding in Visual Studio) do the following:
  1. Remove the VS 11 DLL references (see above) from your project(s) and corresponding namespace declarations.
  2. Add the Windows 8 run-time DLL (stored in the GAC). This should also be registered as a local COM server.

    Windows.Help.Runtime.dll
Note that Windows 8 does not provide an equivalent to Microsoft.VisualStudio.Help.dll for rendering support. In this case you need to render yourself or use the renderer provided in the demo code (see HV2Lib assembly).

Errors 

All methods of the API use HRESULT to indicate success or failure of the action. S_OK, zero, is used to indicate success. Standard COM HRESULT errors are used wherever possible. In C# where there is usually no error returned, the best practice is to use Try-Catch blocks. EG. Open an invalid file path or corrupt catalog and you will catch an exception.

Windows.Help.Runtime.ICatalog

The main API classes are Catalog (Interface ICatalog) and CatalogRead.

private Catalog catalog = new Catalog();

The Catalog object is used to Open & Close help catalogs.
  • void Open(string path, string[] prioritizedLocales)
  • void OpenMshx(string path)   
  • void Close()   
  • string ContentPath { get; }   
  • bool IsOpen { get; }
  • ICatalogReadWriteLock GetReadWriteLock(string catalogPath)   
  • int IsLanguageSupportAvailable(string lang)

ICatalog.Open() 

Before you can read from a help catalog you must open it.

void Open(string path, string[] prioritizedLocales)

path -- This is the full directory path to the catalog you want to open.

prioritizedLocales -- Specify which locale (language) content of the catalog to open. This is a prioritized string array so you can define which locale content is utilized first. (e.g. en-US, ja-JP, etc).

Notes:
  • ICatalog property IsOpen will confirm the catalog did open, and you will catch an exception if you try and open an invalid catalog or use an invalid catalog path.
  • Call catalog.OpenMshx() instead of catalog.Open()to open a .mshx style catalog.
  • Call method catalog.Close() when done with a catalog to free up memory. Otherwise the the catalog object dispose will close the catalog when it goes out of scope.
  • Use property catalog.IsOpen to check if a catalog is currently open.
  • Use property catalog.ContentPath to return the content path of the open catalog.
See also Catalogs 

void ExampleOpenClose()    // C++ Example
{
    HRESULT hr = S_OK;

    // init COM
    hr = CoInitialize(NULL);
    ICatalogPtr helpCatalog;
    
    // create the catalog instance
    hr = helpCatalog.CreateInstance(__uuidof(Catalog));
    
    // build prioritized locale list
    CComSafeArray<BSTR> saBstrArray;
    saBstrArray.Add(_T("en-US"), true);
    SAFEARRAY** safe = saBstrArray.GetSafeArrayPtr();
    
    // open catalog
    helpCatalog->Open(_T("c:\\windows\\help"), *safe);
    
    // do something with the catalog
    if (helpCatalog->IsOpen)
    {
        // close catalog
        hr = helpCatalog->Close();
    }

    // clean up
    CoUninitialize();
}

ICatalog.OpenMshx() 

Same as catalog.Open() but opens a .mshx style catalog file instead of a catalog folder (local store). 

void OpenMshx(string path)

path -- Full path to a .mshx catalog file. 

See also Catalogs 

void ExampleOpenCloseMSHX()   // C++ Code Example
{
    HRESULT hr = S_OK;
    
    // init COM
    hr = CoInitialize(NULL);
    ICatalogPtr helpCatalog;
    
    // create the catalog instance
    hr = helpCatalog.CreateInstance(__uuidof(Catalog));
    
    // open mshx catalog
    helpCatalog->OpenMshx(_T("c:\\windows\\help\\widget.mshx"));
    
    // do something with the catalog
    if (helpCatalog->IsOpen)
    {
        // close catalog
        hr = helpCatalog->Close();
    }
    
    // clean up
    CoUninitialize();
}

ICatalog.Close() 

Caller is required to close a open catalog once finished with it.  

void Close()

Note:
  • Catalogs can be open using catalog.Open() and catalog.OpenMshx().
  • Use property catalog.IsOpen to check if a catalog object is currently open.

ICatalog.ContentPath 

If a catalog is open this property returns the full path the catalog's <catalog>\ContentStore\ folder.

string ContentPath { get; }   


ICatalog.IsOpen 

If a catalog is open this property returns True.

bool IsOpen { get; }


ICatalog.GetReadWriteLock()

Think of a catalog as a shared database that Microsoft code reads and modified directly. If for some reason you wrote a application that reads or writes directly to a catalog you would need to use these locks to prevent read/write clashes.

If a catalog is open this method returns an ICatalogReadWriteLock object containing the catalogs locking status. The returned object also contains methods to set the locking state of a catalog.

ICatalogReadWriteLock GetReadWriteLock(string catalogPath)   

Mostly of use to Microsoft. The API demo code calls this on a timer loop and you can see the catalog locks being set by the VS 11 Content Manager when the catalog is being updated.

ICatalogReadWriteLock
bool EnterReadLock(int timeout)
bool EnterWriteLock(int timeout)
void ExitNonBlockingWriteOperation()
void ExitReadLock()
void ExitWriteLock()
bool StartNonBlockingWriteOperation(int timeout)
bool IsCurrentlyNonBlockingWriteLocked { get; }
bool IsCurrentlyWriteLocked { get; }

Notes:  (???)
  • Before accessing catalog files directly check the catalogs locking status using IsCurrentlyNonBlockingWriteLocked and IsCurrentlyWriteLocked.
  • The rest I'm guessing. Will update later.

// C++ Code Example
ICatalogPtr helpCatalog;


// create the catalog instance
hr = helpCatalog.CreateInstance(__uuidof(Catalog));

ICatalogReadWriteLockPtr lockPtr = helpCatalog->GetReadWriteLock(catalogPath);

ICatalog.IsLanguageSupportAvailable()

The method returns 0 if the language (eg. "en-US") is supported by the operating system.  This call is mostly of interest to Microsoft. 

int IsLanguageSupportAvailable(string lang)

The API code demo (see catalog sub-page) shows exactly what this does.

Returns an integer which reflects whether natural language support is installed on the system
0 – supported
1000 – if the language name is invalid or not recognized
1001 – if the ISearchLanguageSupport is missing
1002 – if IWordBreaker interface for the language cannot be loaded
1003 – if IStemmer interface for the language cannot be loaded

C# Example Code

A simple example of opening, accessing and closing a catalog.

using Microsoft.VisualStudio.Help.Runtime;

...


private Catalog _catalog = new Catalog();
private CatalogRead _catalogRead = new CatalogRead();


// Open an English Catalog


String catalogPath = @"C:\ProgramData\Microsoft\HelpLibrary2\Catalogs\VisualStudio11";
String locale = "en-US";
_catalog.Open(catalogPath, new String[] { locale });


// Get top level TOC topics


ITopicCollection topics = _catalogRead.GetTableOfContents(_catalog, "-1", null, TocReturnDetail.TocRootNodes);


for (int i = 0; i < topics.Count; i++)
{
    topics.MoveTo(i);
    Topic topic = (Topic) topics.Current;
    ....
}


// Close catalog 


if (_catalog.IsOpen)
_catalog.Close();


Windows.Help.Runtime.ICatalogRead

CatalogRead (Interface ICatalogRead) gives us read access to catalog files and data (Search/Index/TOC/Files etc). 

private CatalogRead catalogRead = new CatalogRead();

These CatalogRead methods take an open catalog object as their first parameter.
  • IStream GetIndexedTopic(ICatalog catalog, string topicId, IHelpFilter filter)
  • ITopic GetIndexedTopicDetails(ICatalog catalog, string topicId, IHelpFilter filter)
  • ITopic GetTopicDetailsForF1Keyword(ICatalog catalog, string[] prioritizedF1Keywords, IHelpFilter filter)
  • IStream GetTopicForF1Keyword(ICatalog catalog, string[] prioritizedF1Keywords, IHelpFilter filter)

  • IKeywordCollection GetKeywords(ICatalog catalog, [bool useCache = true])
  • ITopicCollection GetSearchResults(ICatalog catalog, string query, IHelpFilter filter, SearchOptions options, int pageSize, int pageNumber, out int totalSearchResults)
  • ITopicCollection GetTableOfContents(ICatalog catalog, string topicId, IHelpFilter filter, TocReturnDetail returnDetail)
  • IStream GetLinkedAsset(ICatalog catalog, string packageName, string path, string locale)
And that's it. All the other classes and enumerators are used by these main API calls.

ICatalogRead.GetIndexedTopic()

Opens an indexed topic file from within a catalog.

IStream GetIndexedTopic(ICatalog catalog, string topicId, IHelpFilter filter)

catalog -- ICatalog object (see above) we want to access.
topicId -- The topic ID of the required topic.
        Defined in the HTML topic using <meta name="Microsoft.Help.Id" content="SomeUniqueId" />.
filter -- Use null for no filtering. Otherwise provide a list of name/value pairs.

The method returns a stream which you should close when you are finished with.

ICatalogRead.GetIndexedTopicDetails()

Gets a Topic object for an indexed topic file from within a catalog.

ITopic GetIndexedTopicDetails(ICatalog catalog, string topicId, IHelpFilter filter)

Parameters are the same as GetIndexedTopic() above.

The method returns a ITopic object.

ICatalogRead.GetTopicForF1Keyword()

Similar to the above except here we specify the topic we want to open by specifying one or more F1 keywords.

IStream GetTopicForF1Keyword(ICatalog catalog, string[] prioritizedF1Keywords, IHelpFilter filter)

ICatalogRead.GetTopicDetailsForF1Keyword()

Same except it returns a Topic object.

ITopic GetTopicDetailsForF1Keyword(ICatalog catalog, string[] prioritizedF1Keywords, IHelpFilter filter)


ICatalogRead.GetKeywords()

Given an open catalog, returns a list of keyword objects (for populating the Index navigation tab).

IKeywordCollection GetKeywords(ICatalog catalog, [bool useCache = true])

Normally you would leave useCache=true for fastest access to the list (but presumable it takes more memory).

Example:

IKeywordCollection keywords = _catalogRead.GetKeywords(_catalog, true);
for (int i = 0; i < keywords.Count; i++)
{
    keywords.MoveTo(i);
    keyword keyword = (Keyword)keywords.Current;
    ....
}

There is also keywords.MoveNext(); that can be used if you are iterating with a foreach(...) { }  loop.

The keyword object has these handy members:

 keyword.DisplayValue holds the keyword display string.
 keyword.IsSubkey tells us if we need to indent the keyword.
 keyword.Topics gives access to the list of result topics associated with the keyword.

Word Wheel Search

We want to type in the edit box (above the keyword list) and select the closest match in the list (the keyword starting with that text).

The MoveToKeyword() method returns the index of the List item we want to select and scroll into view.

int i = keywords.MoveToKeyword(text);   //where text is the text typed
if (i >= 0 && i <= keywords.Count)
{
   ...



ICatalogRead.GetSearchResults()

Given an open catalog, performs a search query on the catalog and returns a list of Topic results.

ITopicCollection GetSearchResults(ICatalog catalog, string query, IHelpFilter filter, SearchOptions options, int pageSize, int pageNumber, out int totalSearchResults)

Search code is also very straight forward.

Here GetSearchResults()  returns a list of topics. 

String query = "StringBuilder";  
HelpFilter filter = null;      // adv filtering not required (we want all search results)
int pageSize = 50;             // number of items per page to return
int pageNumber = 1;            // which page of results to return 
int _totalAvailableHits = 0;   // total number of hits returned 

ITopicCollection topics = _catalogRead.GetSearchResults(_catalog, query, filter, SearchOptions.None, pageSize, pageNumber, out _totalAvailableHits);

And again we can iterate through the returned topic list (see details for ITopicCollection and Topic in TOC page help).

These Search options can be OR'd together if required.

SearchOptions.None no options.
SearchOptions.OrSearchOverride changes search terms "x y", normally interpreted "x AND y",  to "x OR y".
SearchOptions.SearchTermHighlight adds highlighting html tags to search result text.


Search Operators

Note that special search prefixes can be concatenated together and prefix any search term.
So when searching for "String AND Lock" this is also valid: "code:c#:keyword:String AND title:Lock".


ICatalogRead.GetTableOfContents()

Given an open catalog, queries the catalog can returns a list of topic objects.

ITopicCollection GetTableOfContents(ICatalog catalog, string topicId, IHelpFilter filter, TocReturnDetail returnDetail)

The GetTableOfContents() method returns a collections of Topic objects, according to the parameters passed in. 

catalog -- An open catalog object (we created that in the Catalog.Open() call).
topicId -- A topic ID (not applicable in the TocRootNodes call). Use "-1" to represent the TOC root node.
filter -- A Filter which is a list of Name\Value pairs. We are not using filters in the demos. We want the full TOC so we pass null (for no filtering).
returnDetail -- Specifies the type of TOC info we want returned (see TocReturnDetail enum).

Here are the main HV2 API calls for building a TOC.

This gives us the root nodes of the TOC.

ITopicCollection topics = _catalogRead.GetTableOfContents(_catalog, "-1", null, TocReturnDetail.TocRootNodes);

This gives us the immediate children of a particular topic.

ITopicCollection topics = _catalogRead.GetTableOfContents(_catalog, topic.Id, null, TocReturnDetail.TocChildren);

TocReturnDetail Enum

TocReturnDetail.TocAncestors  returns a list of parent topics of the specified node up to the root.
TocReturnDetail.TocChildren  returns a list of child topics of the specified node.
TocReturnDetail.TocDescendants  returns a list of every topic under the specified node. 
TocReturnDetail.TocRootNodes  returns a list of all level 0 nodes (children of TopicID="-1").
TocReturnDetail.TocSiblings  returns a list of all nodes at the same level with the same parent. 

ICatalogRead.GetLinkedAsset()

This call reads asset files (topics, css, images etc) from a catalog package (help file).

IStream GetLinkedAsset(ICatalog catalog, string packageName, string path, string locale)

The caller should close the returned stream as soon as it is finished with it.

catalog -- An open catalog object (we created that in the Catalog.Open() call).
packageName -- Specify the package in the catalog the target file lives in. eg. "MyHelpFile.mshc". This can be extracted from the Topic object returned by most calls.
path -- The path of the file we want returned. eg. "\border.gif"
locale -- Specify local content locale of interest. eg. "en-US"


Other Classes

All other classes and enums are used used by the ICatalogRead methods.

MemoryIStream, FileIStream and HelpReader

MemoryIStream, FileIStream and HelpReader are used internally and exposed via COM. Most developers won't use these.

ICatalog.ICatalogReadWriteLock

Object returned by calling ICatalog.GetReadWriteLock(CatalogPath).
Use the object to get or set a catalogs read/write locks.

IHelpFilter, IHelpKeyValuePair

Various ICatalogRead methods expect an IHelpFilter list of IHelpKeyValuePair items.
This is how catalog filtering is achieved. The Key is not case sensitive. A key/value pair may look something like this: "topiclocale","en-US". Just pass in null if filtering is not required.

IKeywordCollection, IKeyword

The ICatalogRead.GetKeywords() call returns an IKeywordCollection collection of Ikeyword items.

ITopicCollection, ITopic

ICatalogRead.GetTableOfContents() & ICatalogRead.GetSearchResults() methods return a collection of ITopic objects.

Topic Class

ITopicCollection is a collection of Topic objects. Here we are getting all Topics from the collection. 

ITopicCollection topics = _catalogRead.GetTableOfContents(_catalog, "-1", null, TocReturnDetail.TocRootNodes);

for (int i = 0; i < topics.Count; i++)
{
    topics.MoveTo(i);
    Topic topic = (Topic) topics.Current;
    ....
}

There is also topics.MoveNext(); that can be used if you are iterating with a foreach(...) { }  loop.

The Topic class has very handy members. Here an example of the contents:

topic.Category                
topic.ContentFilter            Visual F#
topic.ContentType              Reference
topic.Description              Returns a string by concatenating...
topic.DisplayVersion          
topic.Id                       489CF6E9-E0A0-457A-9E9B-BF630A40A25B
topic.Locale                   en-US
topic.Package                  Visual_Studio_21800792_VS_100_en-us_1.mshc;\R402.htm
topic.ParentId                 A5FDA9CD-D71F-4271-A6A4-AB4CAA0BE550
topic.TableOfContentsHasChildren False
topic.TableOfContentsPosition  10
topic.Title                    String.replicate Function (F#)
topic.TopicLocale              EN-US
topic.TopicVersion             100
topic.Url                      Visual_Studio_21800792_VS_100_en-us_1.mshc;\R402.htm
topic.Vendor                   Microsoft

Note especially...
  • topic.TableOfContentsHasChildren tells us if we can expand the node.
  • topic.Title gives us the node text.
  • topic.ParentId gives us the topic ID of the topics patent topic in the TOC.

enum SearchOptions

This is an enumeration used by ICatalogRead.GetSearchResults().
  • none=0;  // Default processing.
  • SearchTermHighlight=1;   // Apply highlighting to search hits.
  • OrSearchOverride=2;   // "OR" search query terms instead of "AND" (the default).

enum TocReturnDetail

This is an enumeration used by ICatalogRead.GetTableOfContents().
  • TocChildren=0;   // Get only children.
  • TocSiblings=1;   // Get only siblings.
  • TocAncestors=2;   // Get only ancestors.
  • TocRootNodes=3;   // Get only root list.
  • TocDescendants=4;  // Get only descendants.



Ċ
Robert Chandler,
Jan 1, 2012, 4:37 AM
Comments