|
Windows Help
WinHelp macros
Using Help
HelpFiles
Searching your application's help file
WinHelp macros
Question
Is it possible to call the WinHelp macro 'Search()' from Delphi?
Answer
A:
Yes, you can do this by a direct call to the Windows API WinHelp function, or
(more easily) by calling the Application.HelpCommand method.
Or (more easily still) you could avoid having to fiddle with pointers to null
terminated strings every time, by going a stage further and encapsulating the
call into a simple procedure like this:
unit Help;
{$X+ {Allow Application.HelpCommand's result to be discarded}
interface
procedure HelpSearch (const Key: string);
implementation
uses
Forms, {for Application}
SysUtils, {for StrPCopy}
WinTypes; {for HELP_PARTIALKEY}
procedure HelpSearch (const Key: string);
{----------------------------------------------------------------}
{ Calls Windows Help engine for a Search on the supplied Key. }
{ If more than one match or no match, brings up Search dialog. }
{----------------------------------------------------------------}
var
AStr255: array[0..255] of char;
PStr255: pointer;
begin
PStr255 := StrPCopy(@AStr255, Key);
Application.HelpCommand(HELP_PARTIALKEY, longint(PStr255));
end;
end.
Using Help
Question
I'm using Application.helpJump to implement context-sensitive help.
Sometimes, however, the topic string I construct isn't in the help file, in
which case winHelp displays "Topic not found" and keeps the user in Help
with a blank screen. Does anyone know of a way to interrogate a WinHelp
file to see if a context string exists, or alternatively a way to extract
all context strings from a help file (then I can write a little loop to see
if the string is there).
Answer
A:
You can support LDLLHandler() in your help system. With that I think you can
check DW_ENDJUMP, lparam1 of it will hold the position of the help topic.
When it fails you can call the callback function RcCloseHfs to close Help.
I suppose there would be a blink that the user may notice, but it may be
tolerable.
The work to do is to create a DLL to support LDLLHandler() and a DLL macro in
the help system to send information to the DLL.
A:
The following code demonstrates how to bring up the WinHelp "Search"
dialog for your application's help file. You can use TApplication's
HelpCommand method to send the Help_PartialKey command to the WinHelp
system. The parameter for this command should be a PChar (cast to a
longint to circumvent typechecking) that contains the string on
which you'd like to search. The example below uses an empty string,
which invokes "Search" dialog and leaves the edit control in the
dialog empty.
procedure TForm1.SearchHelp;
var
P: PChar;
begin
Application.HelpFile := 'c:\delphi\bin\delphi.hlp';
P := StrNew('');
Application.HelpCommand(Help_PartialKey, longint(P));
StrDispose(P);
end;
DISCLAIMER: You have the right to use this technical information
subject to the terms of the No-Nonsense License Statement that
you received with the Borland product to which this information
pertains.
A:
Here's my Help unit. You may find some of the routines down
at the bottom useful - e.g. look for WinHelpTopic. Let me
know if you need any of the routines which it calls:
{----------------------------------------------------------------}
{ }
{ The Pascal Factory - Delphi Tools Library - Help unit }
{ }
{ Routines for easy implementation of Windows Help & Hints. }
{----------------------------------------------------------------}
{c 1990-1996 Mike O'Hanlon, The Pascal Factory.}
unit Help;
{$R HELPCURS.RES}
interface
uses
Controls, {for TControl}
Graphics; {for TColor}
procedure PaleYellowHints;
function QuestionMarkCursor: Boolean;
procedure RemoveHint (var Hint: THintWindow);
function RevealHint (Control: TControl; Color: TColor)
: THintWindow;
procedure ResetQuestionMarkCursor;
procedure SetQuestionMarkCursor;
procedure WinHelpContents;
procedure WinHelpForForm (Sender: TObject);
procedure WinHelpForFormTab (Sender: TObject);
procedure WinHelpQuit;
procedure WinHelpSearch;
procedure WinHelpTopic (const Topic: string);
implementation
uses
Basics, {for RemoveFirst}
Classes, {for Bounds}
Errors, {for Err handling}
ExtCtrls, {for TNotebook}
Extras, {for InstallCursor}
Forms, {for TForm}
SysUtils, {for StrPCopy}
TabNotBk, {for TTabbedNotebook}
WinProcs, {for DrawText}
WinTypes; {for HELP_PARTIALKEY}
const
crQuestionMark = 1;
var
PreviousCursor: TCursor;
procedure PaleYellowHints;
{----------------------------------------------------------------}
{ Makes all Hints for the application a bit paler than standard. }
{----------------------------------------------------------------}
begin
Application.HintColor := $00C1FFFF; {Very pale yellow}
end;
function QuestionMarkCursor: Boolean;
{----------------------------------------------------------------}
{ Returns state of cursor: true for question mark, else false. }
{----------------------------------------------------------------}
begin
if Screen.Cursor = crQuestionMark
then QuestionMarkCursor := true
else QuestionMarkCursor := false;
end;
procedure RemoveHint (var Hint: THintWindow);
{----------------------------------------------------------------}
{ Releases the window handle of a Hint previously popped up with }
{ RevealHint. }
{----------------------------------------------------------------}
begin
Hint.ReleaseHandle;
Hint.Free;
Hint := nil;
end;
function RevealHint (Control: TControl; Color: TColor)
: THintWindow;
{----------------------------------------------------------------}
{ Pops up Hint window for the specified Control, and returns a }
{ reference to the hint object so it may subsequently be removed }
{ with RemoveHint. }
{----------------------------------------------------------------}
var
Outcome: THintWindow;
ShortHint: string;
AShortHint: array[0..255] of Char;
HintPos: TPoint;
HintBox: TRect;
HeightOfText: Integer;
begin
{ Create the window: }
Outcome := THintWindow.Create(Control);
if Color <> 0 then
Outcome.Color := Color;
{ Get first half of hint up to '|': }
ShortHint := GetShortHint(Control.Hint);
{ Calculate Hint Window position & size: }
HintPos := Control.ClientOrigin;
Inc(HintPos.Y, Control.Height + 6);
HintBox := Bounds(0, 0, Screen.Width, 0);
HeightOfText := DrawText(Outcome.Canvas.Handle,
StrPCopy(PChar(@AShortHint), ShortHint), -1, HintBox,
DT_CALCRECT or DT_LEFT or DT_WORDBREAK or DT_NOPREFIX);
OffsetRect(HintBox, HintPos.X, HintPos.Y);
Inc(HintBox.Right, 6);
Inc(HintBox.Bottom, 2);
{ Now show the window: }
Outcome.ActivateHint(HintBox, ShortHint);
RevealHint := Outcome;
end; {RevealHint}
procedure ResetQuestionMarkCursor;
{----------------------------------------------------------------}
{ Resets cursor from Question Mark cursor. }
{----------------------------------------------------------------}
begin
PreviousCursor := 0;
Screen.Cursor := PreviousCursor;
end;
procedure SetQuestionMarkCursor;
{----------------------------------------------------------------}
{ Store cursor (for later reset) and set Question Mark cursor. }
{----------------------------------------------------------------}
begin
PreviousCursor := Screen.Cursor;
Screen.Cursor := crQuestionMark;
end;
procedure WinHelpCommand (Command: Word; Data: Longint);
{----------------------------------------------------------------}
{ Calls Application.HelpCommand with the supplied parameters. }
{ Displays an error message if HelpCommand returns false and }
{ Debug information is on. }
{----------------------------------------------------------------}
var
CommandStr: string;
begin
if not Application.HelpCommand(Command, Data) then
{$IFOPT D+}
begin
case Command of
HELP_CONTENTS: CommandStr := 'HELP_CONTENTS';
HELP_PARTIALKEY: CommandStr := 'HELP_PARTIALKEY';
HELP_QUIT: CommandStr := 'HELP_QUIT';
else CommandStr := 'unknown';
end; {case}
Err(['Proc: WinHelpCommand',
'Meth: Application.HelpCommand',
'Win: WinHelp',
'HelpCommand call returned false result',
'Command was ' + CommandStr]);
end;
{$ENDIF}
end;
procedure WinHelpContents;
{----------------------------------------------------------------}
{ Calls the Windows Help engine and displays the Contents page. }
{----------------------------------------------------------------}
begin
WinHelpCommand(HELP_CONTENTS, 0);
end; {WinHelpContents}
procedure WinHelpForForm (Sender: TObject);
{----------------------------------------------------------------}
{ Calls the Windows Help engine with a Topic built from the }
{ ClassName (less leading 'T') of the parent Form of the Sender. }
{----------------------------------------------------------------}
begin
{ Go up parent tree until Form is found: }
while not (Sender is TForm) do
Sender := TWinControl(Sender).Parent;
WinHelpTopic(RemoveLeading('T', Sender.ClassName));
end; {WinHelpForForm}
procedure WinHelpForFormTab (Sender: TObject);
{----------------------------------------------------------------}
{ Calls the Windows Help engine with a Topic built from the }
{ ClassName (less leading 'T') of the parent Form of the Sender. }
{ If the form has a (visible) Notebook or TabbedNotebook on it, }
{ the name of the displayed Tab (less '&' accelerator character) }
{ is appended to the Topic. }
{----------------------------------------------------------------}
var
Tab: string;
I: Integer;
begin
{ Go up parent tree until Form is found: }
while not (Sender is TForm) do
Sender := TWinControl(Sender).Parent;
{ Check components on Form for visible Notebook/TabbedNotebook: }
Tab := '';
with TForm(Sender) do
for I := 0 to ComponentCount - 1 do
if TControl(Components[I]).Visible then
if (Components[I] is TNotebook) then
begin
with TNotebook(Components[I]) do
Tab := '_'+ RemoveFirst('&', Pages[PageIndex]);
Tab := RemoveAll(' ', Tab);
Break; {out of for loop}
end
else if (Components[I] is TTabbedNotebook) then
begin
with TTabbedNotebook(Components[I]) do
Tab := '_'+ RemoveFirst('&', Pages[PageIndex]);
Tab := RemoveAll(' ', Tab);
Break; {out of for loop}
end;
WinHelpTopic(RemoveLeading('T', Sender.ClassName) + Tab);
end; {WinHelpForFormTab}
procedure WinHelpQuit;
{----------------------------------------------------------------}
{ Should be called before app exits. WinHelpQuit calls Windows }
{ Help engine and informs it that Help is no longer needed. If }
{ no other applications have asked for Help, WinHelp is closed. }
{----------------------------------------------------------------}
begin
WinHelpCommand(HELP_QUIT, 0);
end; {WinHelpQuit}
procedure WinHelpSearch;
{----------------------------------------------------------------}
{ Calls the Windows Help engine and brings up the Search dialog. }
{----------------------------------------------------------------}
const
ForceSearch = '???';
var
AStr255: array[0..255] of Char;
Data: Longint;
begin
WinHelpContents;
Data := Longint(StrPCopy(PChar(@AStr255), ForceSearch));
WinHelpCommand(HELP_PARTIALKEY, Data);
end; {WinHelpSearch}
procedure WinHelpTopic (const Topic: string);
{----------------------------------------------------------------}
{ Calls Windows Help engine and looks for the supplied Topic. }
{ If more than one match or no match, brings up Search dialog. }
{----------------------------------------------------------------}
var
AStr255: array[0..255] of Char;
Data: Longint;
begin
Data := Longint(StrPCopy(PChar(@AStr255), Topic));
WinHelpCommand(HELP_PARTIALKEY, Data);
end; {WinHelpTopic}
initialization
PreviousCursor := 0;
InstallCursor('QUESTIONMARKCURSOR', crQuestionMark);
end.
Hope something in there (Win)Helps...
A:
I have written a THelper component, which provides additional Help
features. Here are the source files HELPER.PAS, HELPCONS.PAS and
HELPER.RC
-------------- chew off here for HELPER.PAS
unit Helper;
interface
uses
SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
Forms, Dialogs;
type
EHelperError = class(Exception)
end;
THelper = class(TComponent)
protected
procedure Check(Condition: Boolean; Operation: Word);
public
procedure ShowContents;
procedure SearchTopic(const Topic: string; Partial: Boolean);
procedure ShowContext(ContextNumber: LongInt); procedure
ShowContextString(const ContextString: string); procedure
SearchDialog; procedure HelpMacro(const MacroName: string);
procedure HelpOnHelp;
end;
procedure Register;
implementation
{$R HELPER.RES}
uses
HelpCons;
procedure Register;
begin
RegisterComponents('Lance', [THelper]);
end;
{ THelper Component }
procedure THelper.Check(Condition: Boolean; Operation: Word);
const
MaxMsg = 64;
var
Msg: PChar;
PasMsg: string;
begin
if not Condition then
begin
Msg := StrAlloc(MaxMsg + 1);
try
LoadString(HInstance, Operation, Msg, MaxMsg);
PasMsg := StrPas(Msg);
raise EHelperError.Create(PasMsg);
finally
StrDispose(Msg);
end;
end;
end;
procedure THelper.SearchTopic(const Topic: string; Partial: Boolean);
var
Key: PChar;
HelpFile: PChar;
Command: Word;
begin
Key := StrAlloc(Length(Topic) + 1);
try
StrPCopy(Key, Topic);
HelpFile := StrAlloc(Length(Application.HelpFile) + 1);
try
StrPCopy(HelpFile, Application.HelpFile);
Check(Application.HelpCommand(HELP_FORCEFILE, 0),
SHelpCantHelp); if Partial then
Command := HELP_PARTIALKEY
else
Command := HELP_KEY;
Check(Application.HelpCommand(Command,
LongInt(Key)), SHelpCantShowHelpFile);
finally
StrDispose(HelpFile);
end;
finally
StrDispose(Key);
end;
end;
procedure THelper.ShowContents;
var
HelpFile: PChar;
begin
HelpFile := StrAlloc(Length(Application.HelpFile) + 1);
try
StrPCopy(HelpFile, Application.HelpFile);
Check(Application.HelpCommand(HELP_FORCEFILE, 0), SHelpCantHelp);
Check(Application.HelpCommand(HELP_CONTENTS,
0), SHelpCantShowTOC);
finally
StrDispose(HelpFile);
end;
end;
procedure THelper.ShowContext(ContextNumber: LongInt);
var
HelpFile: PChar;
begin
HelpFile := StrAlloc(Length(Application.HelpFile) + 1);
try
StrPCopy(HelpFile, Application.HelpFile);
Check(Application.HelpCommand(HELP_FORCEFILE, 0), SHelpCantHelp);
Check(Application.HelpCommand(HELP_CONTEXT,
ContextNumber), SHelpCantShowCTX);
finally
StrDispose(HelpFile);
end;
end;
procedure THelper.SearchDialog;
begin
SearchTopic('', True);
end;
procedure THelper.HelpMacro(const MacroName: string);
var
Key: PChar;
HelpFile: PChar;
Command: Word;
begin
Key := StrAlloc(Length(MacroName) + 1);
try
StrPCopy(Key, MacroName);
HelpFile := StrAlloc(Length(Application.HelpFile) + 1);
try
StrPCopy(HelpFile, Application.HelpFile);
Check(Application.HelpCommand(HELP_FORCEFILE, 0),
SHelpCantHelp); Check(Application.HelpCommand(HELP_COMMAND,
LongInt(Key)), SHelpCantMacro);
finally
StrDispose(HelpFile);
end;
finally
StrDispose(Key);
end;
end;
procedure THelper.HelpOnHelp;
begin
HelpMacro('HelpOn()');
end;
procedure THelper.ShowContextString(const ContextString: string);
begin
Check(Application.HelpCommand(HELP_FORCEFILE, 0), SHelpCantHelp);
Check(Application.HelpJump(ContextString), SHelpCantShowTopic);
end;
end.
---------------- chew here for HELPCONS.PAS
unit Helpcons;
interface
const
SHelpCantHelp = 30000;
SHelpCantShowTopic = SHelpCantHelp + 1;
SHelpCantShowContext = SHelpCantShowTopic + 1;
SHelpCantShowHelpFile = SHelpCantShowContext + 1;
SHelpCantShowTOC = SHelpCantShowHelpFile + 1;
SHelpCantShowCTX = SHelpCantShowTOC + 1;
SHelpCantMacro = SHelpCantShowCTX + 1;
implementation
end.
---------------- chew here for HELPERRC
#include "helpcons.pas"
STRINGTABLE
{
SHelpCantHelp, "Can't open helpfile"
SHelpCantShowTopic, "Can't show help topic"
SHelpCantShowContext, "Can't show Helpcontext"
SHelpCantShowHelpFile, "Can't search helpfile"
SHelpCantShowTOC, "Can't show help contents"
SHelpCantShowCTX, "Can't show help by contextnumber"
SHelpCantMacro, "Can't execute help macro"
}
HelpFiles
Question
Can you please tell me how to execute a .hlp file from my app.?
Answer
A:
Executing help file in delphi is very easy. All you have to do is just
assigning Application.HelpFile property and the HelpContext property of each
component you have.
Following example demonstrate how to call a help content in 'MYHELP.HLP'
assigned with a context number on [MAP] section in your help project file.
You can get the help content by pressing F1 or the help button (HelpBtn).
.........
[MAP]
demo 2000;
.........
procedure Form1.FormCreate(sender: TObject);
begin
Application.HelpFile := 'MYHELP.HLP';
HelpContext := 2000;
end;
procedure Form1.HelpBtnClick(Sender:TObject);
begin
Application.HelpContext(HelpContext);
end;
A:
Begin
Application.HelpCommand(HELP_CONTENTS, 0);
end;
Pop that into an event handler. Make sure you specify the application
help file in the project options first.
Searching your application's help file
Question
How can I search in application's help file?
Answer
{
The following code demonstrates how to bring up the WinHelp "Search"
dialog for your application's help file. You can use TApplication's
HelpCommand method to send the Help_PartialKey command to the WinHelp
system. The parameter for this command should be a PChar (cast to a
longint to circumvent typechecking) that contains the string on
which you'd like to search. The example below uses an empty string,
which invokes "Search" dialog and leaves the edit control in the
dialog empty.
}
procedure TForm1.SearchHelp;
var
P: PChar;
begin
Application.HelpFile := 'c:\delphi\bin\delphi.hlp';
P := StrNew('');
Application.HelpCommand(Help_PartialKey, longint(P));
StrDispose(P);
end;
|