Windows help devolution

I have been writing Windows help files for nearly 30 years. It’s a very time consuming process to set up and maintain application help files. And just when I think I have a stable, workable system, Microsoft pulls the rug out from underneath me.

With the introduction of Windows Vista in 2006, Microsoft deprecated WinHelp and no longer includes it with the factory images of Windows Vista, Windows 7 and Windows 8.

HTML_help is Microsoft’s replacement for WinHelp. However, the Windows HTML_help viewer is crippled. It will only open CHM help files on a PC, not those stored on an intranet. Instead of content, the viewer displays the absolutely meaningless “Navigation canceled” message:
HTML_help

I have never understood this. An intranet is an internal network, so why in the world would it be considered a security risk to open a file on your own internal network? Apparently, Internet Explorer (tightly integrated into the Windows OS), is not able to discern the difference between the internet and an intranet.

So, I have been sticking with WinHelp as it is freely available for download from Microsoft for Vista, Windows 7 and (surprisingly) Windows 8, with both 32- and 64- bit versions:

Not until my PC at work was (finally) updated to Windows 7, did I realize that WinHelp is now just as useless as HTML_help. Windows 7 now blocks WinHelp from opening HLP help files stored on an intranet.

Again, WTF? What is the security risk of opening a file on your own internal intranet?

I could not find a trustworthy third party HLP file viewer, so I decided to switch to the CHM help format and seek out a replacement for Microsoft’s HTML_help viewer for intranet applications. After hours of web searching, I eventually found xCHM, a free, open-source, multi-platform, functional replacement for Microsoft’s HTML_help viewer.

Although it doesn’t have all the bells and whistles, xCHM does, at least, open CHM help files stored on an intranet.

In order to utilize xCHM, the help calls in APK had to be rewritten. Logically there are three scenarios:

  1. If the program is running from a local drive, the default help handling system is called.
  2. If the program is running on an intranet, and xCHM is available, then xCHM is called to display the relevant help topic.
  3. If on an intranet, and xCHM is not found, then an error dialog is displayed with a link to web help on rxkinetics.com.

Code snippets

Determine if the program is running locally or via intranet:

01
function TfrmMain.IsOnLocalDrive(): Boolean;
02
var
03
  aDrive: string;
04
begin
05
  aDrive := ExtractFileDrive(Application.ExeName);
06
  if (GetDriveType(PChar(aDrive)) = DRIVE_REMOVABLE) or
07
     (GetDriveType(PChar(aDrive)) = DRIVE_FIXED) then
08
    Result := True
09
  else
10
    Result := False;
11
end;
12

Determine which help system is available:

01
function TfrmMain.LocalHelpAvailable(): integer;
02
begin
03
   if IsOnLocalDrive then
04
      result := 1
05
   else
06
      begin
07
         if XchmInstalled then
08
            result := 2
09
         else
10
            result := 0;
11
      end;
12
end;

Intercept the application help call and choose which help system to use:

01
function TfrmMain.ApplicationEvents1Help(Command: Word; Data: Integer;
02
  var CallHelp: Boolean): Boolean;
03
var
04
   MyHelpKeyWord : string;
05
begin
06
   case LocalHelpAvailable of
07
     0: begin
08
           // On network and xchm is *not* installed
09
           CallHelp := False;
10
           frmHelp_Link.ShowModal;
11
        end;
12
     1: CallHelp := True;  // Local drive
13
     2: begin
14
           // On network and xchm *is* installed
15
           CallHelp := False;
16
           // Get HelpContext of current active control
17
           MyHelpKeyWord := IntToStr(Screen.ActiveControl.HelpContext);
18
           // If control HelpContext is blank -> Get Parent HelpContext
19
           if MyHelpKeyWord='' then
20
              begin
21
                 MyHelpKeyWord := IntToStr(Screen.ActiveControl.Parent.HelpContext);
22
                 // If parent is blank and parent is not a form, get form HelpContext
23
                 if MyHelpKeyWord='' then
24
                    begin
25
                       if Screen.ActiveControl.Parent <> Screen.ActiveControl.Owner then
26
                          MyHelpKeyWord := IntToStr(Screen.ActiveForm.HelpContext);
27
                       // Fallback: if control, parent, and form HelpContext are all blank -> display start up topic
28
                       if MyHelpKeyWord='' then
29
                          MyHelpKeyWord := '10';
30
                    end;
31
              end;
32
           ShellToXchm(MyHelpKeyWord);
33
        end;
34
   end;
35
end;

Shell out to xCHM:

1
procedure TfrmMain.ShellToXchm(HelpTopic:string);
2
var
3
   strParameters : string;
4
begin
5
   // Create parameter string -- Requires short path name!
6
   strParameters := ' /c ' + HelpTopic + ' ' + GetShortName(PathName) + 'apk.chm';
7
   // Shell out to xCHM
8
   ShellExecute(Application.Handle, 'open', 'xchm.exe', PChar(strParameters), PChar(PathName), SW_SHOW);
9
end;

Looking back, this has probably been an exercise in futility. It seems as though most pharmacists either don’t know there is a help system built into the program, or they don’t care. Either way, no one has bothered to contact me to report a problem. Why am I not at all surprised?

Comments are closed.