Showing posts with label HTML Help. Show all posts
Showing posts with label HTML Help. Show all posts

Monday, March 18, 2019

Minimizing West Wind HTML Help Builder Uploads

I’ve been using West Wind HTML Help Builder for about twenty years (it’s hard to believe it’s been that long, but I checked) and still love it as much as ever. I looked at a lot of HTML Help generating tools over the years and it’s still the best one in my opinion.

One of the features I love about it is the ability to generate not just a CHM file for a desktop application but also HTML files for a web application or to post the documentation on a web site. For example, we provide online versions of the developer and end-user documentation for our products (for example, for the Stonefield Query report designer), both so prospective customers can review it before they buy and so we can point customers asking support questions to the relevant topic with a simple URL instead of “open the help, then navigate to …”.

At a recent conference, I was asked if there’s a way to reduce the number of files needed to be deployed to a web site to provide online help. I used to deploy the files directly from the project folder so I wrote some code that uploaded only those files that are actually required because there are a ton of files that aren’t. Fortunately, I don’t need to do that anymore because a new feature in Help Builder does this automatically: after building the help, click the Copy to Folder button to create a deployment folder with only the required files, then use something like FileZilla to upload the contents of that folder to the web site. FileZilla and other FTP programs are typically faster than homegrown code like mine or the code used for the FTP Web Upload function in Help Builder, likely because they use multithreading to upload several files or chunks of files at once rather than one at a time.

However, even the Copy to Folder function copies a few more files than necessary. Here are files you can delete from the deployment folder before uploading (which of course you could automate with a PRG or PowerShell script):

  • bmp: any images for topic types you aren’t using, such as classcontructor.png. Typically, the only ones I keep are folder.png, header.png, index.png, topic.png, and whatsnew.png. Also, the contents of the image subdirectory of the bmp folder aren’t used anywhere and can be deleted.
  • html: this folder is empty and can be ignored.
  • images\images: the only file in this folder is wwhelp.png and it doesn’t appear to be used anywhere (there’s another copy of this file in images, which is used in the various HTML documents unless you customize the templates to not use it as I have).
  • templates\scripts: ww.jquery.js: this is the unminified version of ww.jquery.min.js.
  • templates\scripts\bootstrap\dist\css: bootstrap.css, bootstrap.css.map, bootstrap-theme.css, bootstrap-theme.css.map: these are unminified versions of other files or map files which aren’t needed.
  • templates\scripts\bootstrap\dist\js: bootstrap.js, npm.js: unminified or unneeded files.
  • templates\scripts\highlightjs\styles: any css file you aren’t using, as determined by the Theme setting in the Content Editor page of the Options dialog. I typically use vs2015.css in my projects so I delete the rest.
  • templates\scripts\jquery: jquery.js, jquery.min.map: unminified or map files.

Removing unused files saves about 1.5 MB, which may not sound like much in these days of large hard drives, but that shaves a bit of time off the upload process.

Thursday, June 23, 2011

Better Online Help Links

I’ve been using Rick Strahl’s West Wind HTML Help Builder for more than a decade and still think it’s the best tool for creating help files. One of the many things I like about it is that in addition to creating a CHM file, it also generates files you can upload to a web site. For example, http://www.stonefieldquery.com/OnlineHelp/EndUser/index.htm is the online version of the Stonefield Query end-user help. I didn’t have to do anything after generating my CHM other than uploading the files HTML Help Builder creates.

There are several reasons why we like having help available online:

  • Potential customers can review the complete help file before downloading the demo if they wish.
  • It’s fully indexed by Google, Bing, etc. so shows up in searches.
  • When someone asks a support question, rather than telling them to bring up the help file, open the “How To” heading, and find the “Configuring Stonefield Query” topic, we can send them a link directly to the online version: Configuring Stonefield Query.

However, one issue with the latter item is that a link like http://www.stonefieldquery.com/OnlineHelp/EndUser/_04a0xwfxe.htm displays the help topic without the rest of the help system: no table of contents or search mechanism. I discovered today that if instead of specifying the page directly, you use it as a parameter for the index page, like http://www.stonefieldquery.com/OnlineHelp/EndUser/index.htm?page=_04a0xwfxe.htm, it displays the full help system with the desired page selected. Learn something new every day!

Thanks again, Rick, for a great tool that makes documentation almost fun to create! (I did say ALMOST; I’m not crazy!)

Wednesday, January 20, 2010

My First HTML Help Builder Add-In

Although I’ve used West Wind HTML Help Builder to create HTML Help (CHM) files for my applications for more than 10 years, and have done lots of advanced things such as supporting dynamic text and generating help projects programmatically, I haven’t created an add-in for it. HTML Help Builder supports add-ins using a simple mechanism: once you’ve registered an add-in, it appears in the Tools, Add-Ins menu, ready to run whenever you need it.

The add-in I created does two things:

  • Fixes the icon for the INDEX topic. Every HTML Help Builder project has one topic of type INDEX, and I use that as the “welcome to this help file” topic. Unfortunately, when it builds the CHM, HTML Help Builder uses the wrong icon for that topic. I always had to manually run HTML Help Workshop, edit the icon for that topic (from “11” to “auto”), and rebuild the CHM file. My add-in does that automatically.
  • Turns on searching for the HTML content. In addition to providing CHM files, we post our help files as HTML on our Web site (for example, the Stonefield Query SDK help file), both so Google can index it and so we can provide links to help topics in support messages without having to say “open the help file, open the “How To” heading, then navigate to the “Whatever” topic”. HTML Help Builder recently added a search function to the HTML files it generates, but the generation of that function is turned off by default and I often forget to turn it on. My add-in automatically changes one of the generated files to enable search.

Add-ins can be VFP code (PRG or APP/EXE), a .Net assembly, or a COM object. You register an add-in using the Tools, Add-In Manager function. This is the only cumbersome part of the process: because the add-ins registry table (AddIns.DBF) is stored in the program folder, under Vista or Windows 7 it’s read-only, so you have to launch HTML Help Builder as administrator. Perhaps in a future release, author Rick Strahl will move this file to a writable folder so this isn’t necessary.

image

In my case, I created a class named FixHelp in FixHelp.PRG, and put the code for the add-in into the Activate method. Here’s the code for the class (thanks to Chris Wolf for handling the 64-bit stuff). It should be easy enough to follow.

#define CSIDL_PROGRAM_FILES 0x0026
#define HKEY_LOCAL_MACHINE -2147483646

define class FixHelp as custom
function Activate(toHelpForm)
local loHelp, ;
lcProjectFile, ;
lcPath, ;
lcFile, ;
lcText, ;
lcProgramFiles, ;
lcRegVCX, ;
loRegistry, ;
lcKey, ;
llGotPath, ;
lcLogFile

* Get a reference to the help object, then figure out the path for the
* current project.

loHelp = toHelpForm.oHelp
lcProjectFile = loHelp.cFileName
lcPath = addbs(justpath(lcProjectFile))

* Turn on searching in case it wasn't turned on when the files were
* generated.

lcFile = lcPath + 'index2.htm'
lcText = filetostr(lcFile)
lcText = strtran(lcText, 'var AllowSearch = false;', ;
'var AllowSearch = true;')
strtofile(lcText, lcFile)

* Remove the image number for the root node so it defaults to "auto".

lcFile = forceext(lcProjectFile, 'hhc')
lcText = filetostr(lcFile)
lcText = strtran(lcText, '' + ;
chr(13) + chr(10), '', 1, 1)
strtofile(lcText, lcFile)

* Find the location of HTML Help Workshop. Try the 32-bit registry key
* first. If that doesn't work, try the 64-bit key.

lcProgramFiles = This.GetSpecialFolder(CSIDL_PROGRAM_FILES)
lcRegVCX = addbs(lcProgramFiles) + ;
'Microsoft Visual FoxPro 9\FFC\Registry.vcx'
loRegistry = newobject('Registry', lcRegVCX)
lcPath = ''
lcKey = '\Microsoft\Windows\CurrentVersion\App Paths\hhw.exe'
llGotPath = loRegistry.GetRegKey('Path', @lcPath, ;
'SOFTWARE' + lcKey, HKEY_LOCAL_MACHINE) = 0
if not llGotPath
llGotPath = loRegistry.GetRegKey('Path', @lcPath, ;
'\SOFTWARE\Wow6432Node' + lcKey, HKEY_LOCAL_MACHINE) = 0
endif not llGotPath

* Compile the CHM file if we found it. Log the results.

if llGotPath
lcPath = This.ShortPath(forcepath('hhc.exe', lcPath))
lcProjectFile = '"' + forceext(lcProjectFile, 'hhp') + '"'
lcLogFile = '"' + addbs(justpath(lcProjectFile)) + 'log.txt"'
erase (lcLogFile)
run &lcPath &lcProjectFile > &lcLogFile
if file(lcLogFile)
declare integer ShellExecute in SHELL32.DLL ;
integer nWinHandle, string cOperation, string cFileName, ;
string cParameters, string cDirectory, integer nShowWindow
ShellExecute(0, 'Open', lcLogFile, '', '', 1)
else
erase (lcLogFile)
endif file(lcLogFile)
else
messagebox('Cannot locate HTML Help Workshop')
endif llGotPath
return .T.
endfunc

* Get the short (8.3) path for the specified path.

function ShortPath(tcPath)
local lcPath, ;
lnLength, ;
lcBuffer, ;
lnResult
declare integer GetShortPathName in Win32API ;
string @lpszLongPath, string @lpszShortPath, integer cchBuffer
lcPath = tcPath
lnLength = 260
lcBuffer = space(lnLength)
lnResult = GetShortPathName(@lcPath, @lcBuffer, lnLength)
return iif(lnResult = 0, '', left(lcBuffer, lnResult))
endfunc

* Get the location of the specified "special" folder.

function GetSpecialFolder(tnFolder)
local lcSpecialFolderPath, ;
lcPath
lcSpecialFolderPath = space(255)
declare SHGetSpecialFolderPath in shell32.dll ;
long hwndOwner, string @cSpecialFolderPath, long nWhichFolder
SHGetSpecialFolderPath(0, @lcSpecialFolderPath, tnFolder)
lcPath = alltrim(lcSpecialFolderPath)
return lcPath
endfunc
enddefine


Now when I want to generate a help file, I click Build Help, select the “Don’t build Help file” option (since my add-in will generate the CHM, there’s no need to do it twice), and let it run. I then choose Tools, Add-Ins, Generate Help File (my add-in) to tweak the generated files and build the CHM. There’s a couple of less manual tasks for my build process.