[Back to OOP SWAG index]  [Back to Main SWAG index]  [Original]

(*
Last week I found a bug in HELPFile.PAS and called Borland.  After describing
the error, the Borland representative agreed that it was a bug and that
it hasn't been reported.  ThereFore, I will describe the bug here and give
a fix to the problem.

Problem:
Recall, HELPFile.PAS is the Turbo Vision Unit that TVDEMO.PAS Uses to
provide on-line help to Turbo Vision Programs.  The problem that occurred
was that if a help panel was brought up that did not contain a cross
reference entry (i.e. hyperText link), and the user pressed [Tab] or
Shift+[Tab] then a run-time error is generated.   notE: the run-time
error is generated if the Program is Compiled With Range Checking on.
if Range checking is off, then unpredicatable results occur.

to see the bug in action, do the following:

Fire up Turbo Pascal 6 and load the TVDEMO.PAS Program (by default it exists
in the TVDEMOS subdirectory).  Make sure Range checking is turned on.
The option is in Options|Compiler.  You will also want to turn debugging
on in both the TVDEMO.PAS and HELPFile.PAS Files.  to do this, you must
edit the source code of both Files and change the {$D-} option to {$D+}
at the beginning of both Files.

Once you have done the above, press Ctrl+F9 to run TVDEMO.  When TVDEMO
comes up, press F1 to bring up the help Window.  Now, press Shift+[Tab]
or [Tab] and a RunTime error 201 will occur.

This bug arises from the fact that the HELPFile.PAS Unit assumes that
there will always be at least one cross reference field on a help panel.
Obviously, this is an invalid assumption.

Luckily, there is an easy solution to the problem.  The following shows
how to change the HELPFile.PAS Program so that this error doesn't occur.
The only Procedure that needs to be changed is THelpViewer.HandleEvent.

*)

Procedure THelpViewer.HandleEvent(Var Event: TEvent);
Var
  KeyPoint, Mouse: TPoint;
  KeyLength: Byte;
  KeyRef: Integer;
  KeyCount: Integer;
{ 1. Add the following Variable declaration }
  n : Integer;

Procedure MakeSelectVisible;
Var
  D: TPoint;
begin
  topic^.GetCrossRef(Selected, KeyPoint, KeyLength, KeyRef);
  D := Delta;
  if KeyPoint.X < D.X then D.X := KeyPoint.X;
  if KeyPoint.X > D.X + Size.X then D.X := KeyPoint.X - Size.X;
  if KeyPoint.Y < D.Y then D.Y := KeyPoint.Y;
  if KeyPoint.Y > D.Y + Size.Y then D.Y := KeyPoint.Y - Size.Y;
  if (D.X <> Delta.X) or (D.Y <> Delta.Y) then Scrollto(D.X, D.Y);
end;

Procedure Switchtotopic(KeyRef: Integer);
begin
  if topic <> nil then Dispose(topic, Done);
  topic := HFile^.Gettopic(KeyRef);
  topic^.SetWidth(Size.X);
  Scrollto(0, 0);
  SetLimit(Limit.X, topic^.NumLines);
  Selected := 1;
  DrawView;
end;

begin
  TScroller.HandleEvent(Event);
  Case Event.What of
    evKeyDown:
      begin
        Case Event.KeyCode of
          kbTab:
            begin
{ 2. Change This...
              Inc(Selected);
              if Selected > topic^.GetNumCrossRefs then Selected := 1;
              MakeSelectVisible;
to this... }
              Inc(Selected);
              n := topic^.GetNumCrossRefs;

              if n > 0 then
              begin
                  if Selected > n then
                      Selected := 1;
                  MakeSelectVisible;
              end
              else
                  selected := 0;
{ end of Change 2 }
            end;
          kbShiftTab:
            begin
{ 3. Change this ...
              Dec(Selected);
              if Selected = 0 then Selected := topic^.GetNumCrossRefs;
              MakeSelectVisible;
to this... }
              Dec(Selected);
              n := topic^.GetNumCrossRefs;
              if n > 0 then
              begin
                  if Selected = 0 then
                      Selected := n;
                  MakeSelectVisible;
              end
              else
                  Selected := 0;
{ end of Change 3 }
            end;
          kbEnter:
            begin
{ 4. Change this...
              if Selected <= topic^.GetNumCrossRefs then
              begin
                topic^.GetCrossRef(Selected, KeyPoint, KeyLength, KeyRef);
                Swithtotopic(KeyRef);
              end;
to this...}
              n := topic^.GetNumCrossRefs;
              if n > 0 then
              begin
                  if Selected <= n then
                  begin
                    topic^.GetCrossRef(Selected, KeyPoint, KeyLength, KeyRef);
                    Switchtotopic(KeyRef);
                  end;
              end;
{ end of Change 4 }
            end;
          kbEsc:
            begin
              Event.What := evCommand;
              Event.Command := cmClose;
              PutEvent(Event);
            end;
        else
          Exit;
        end;
        DrawView;
        ClearEvent(Event);
      end;
    evMouseDown:
      begin
        MakeLocal(Event.Where, Mouse);
        Inc(Mouse.X, Delta.X); Inc(Mouse.Y, Delta.Y);
        KeyCount := 0;
        Repeat
          Inc(KeyCount);
          if KeyCount > topic^.GetNumCrossRefs then Exit;
          topic^.GetCrossRef(KeyCount, KeyPoint, KeyLength, KeyRef);
        Until (KeyPoint.Y = Mouse.Y+1) and (Mouse.X >= KeyPoint.X) and
          (Mouse.X < KeyPoint.X + KeyLength);
        Selected := KeyCount;
        DrawView;
        if Event.Double then Switchtotopic(KeyRef);
        ClearEvent(Event);
      end;
    evCommand:
      if (Event.Command = cmClose) and (Owner^.State and sfModal <> 0) then
      begin
        endModal(cmClose);
        ClearEvent(Event);
      end;
  end;
end;

[Back to OOP SWAG index]  [Back to Main SWAG index]  [Original]