home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 16 Announce
/
16-Announce.zip
/
SEMINAR2.ZIP
/
SEMINAR2.DOC
Wrap
Text File
|
1991-11-27
|
17KB
|
364 lines
Using the OS/2 Help Manager
---------------------------
Written by:
Larry Salomon, Jr. (aka 'Q')
OS/2 Applications and Tools
IBM T.J. Watson Research Center
Yorktown Heights, NY
(LARRYS@YKTVMV.BITNET)
(larrys@watson.ibm.com)
(larrys@ibmman.watson.ibm.com)
(larrys@ibmman2.watson.ibm.com)
This seminar may be distributed in any form, providing that no
modifications are made to the text, unless done so by the author.
This, and other seminars, can be received via anonymous ftp from the
following sites:
Site IP Address Directory
---- ---------- ---------
cs.unc.edu 129.109.136.138 /pub/os2.seminars
network.ucsd.edu 128.54.16.3 /pub/os2.seminars
Abstract: the OS/2 Help Manager provides a very useful function to
applications - online help. This seminar will attempt to demonstrate how
to enable your applications to use the Help Manager.
Disclaimer: I do not claim to know everything about this subject. I
simply know enough about this subject to warrant the writing of this
seminar with the intent of making it easier on those who want to know
more.
Audience: this seminar is directed at C programmers with good PM
programming experience. Function prototypes will be taken from the OS/2
1.3 toolkit.
Contact: any questions, comments, etc. can be sent directly to me at one
of the addresses listed above (in the order of preference and highest
rate of successful delivery).
So You Want to Use the Help Manager?
------------------------------------
One of the many very useful features provided by OS/2 is the Help
Manager. Using it, an application can provide field and context
sensitive help online for the user to get out of those "sticky
situations" that they always seem to find themselves in.
However, enabling your application to use the Help Manager is not a
five-minute task, by any means. Ironically, the only documentation (that
I have ever found) on doing this is in the Programming Guide, which comes
with the Technical Reference documentation.
In your application, there are three sections that need to be modified or
created before "you are in business":
Code
Resource definitions
Help panel definitions
Before I discuss these further, it should be noted that help is usually
associated with frame windows. Dialogs that are displayed as a result of
some user action on the frame normally use the help instance associated
with the frame that owns the dialog.
Code
----
The coding aspect of providing online help can be further split into two
parts: initialization/termination and message handling. Initialization
can be done at any time, and consists of a HELPINIT structure and the
WinCreateHelpInstance/WinAssociateHelpInstance APIs.
typedef struct {
USHORT cb;
ULONG ulReturnCode;
PSZ pszTutorialName;
PHELPTABLE phtHelpTable;
HMODULE hmodHelpTableModule;
HMODULE hmodAccelActionBarModule;
USHORT idAccelTable;
USHORT idActionBar;
PSZ pszHelpWindowTitle;
USHORT usShowPanelId;
PSZ pszHelpLibraryName;
} HELPINIT;
cb - the size of the HELPINIT structure
ulReturnCode - initialized by WinCreateHelpInstance to
indicate any errors that have occured but did
not prevent creation of the instantiation.
pszTutorialName - points to a string containing the default
tutorial name. This should be NULL if your
application does not have a tutorial.
phtHelpTable - points to the help table. If (and we will do
it this way) the help table is defined in a
resource file, the high word should be 0xFFFF
and the low word should contain the resource
id.
hmodHelpTableModule - the module handle of the DLL to be used when
retrieving resources or NULL if the .EXE file
contains the resources.
hmodAccelActionBarModule - the module handle of the DLL to be when
loading the accelerator table and action bar
to be used by the Help Manager or NULL if the
.EXE file contains the resources.
idAccelTable - the resource id of the custom accelerator
table or 0 if none exists.
idActionBar - the resource id of the custom action bar or 0
if none exists.
pszHelpWindowTitle - points to a string to be used as the title for
the online help window.
usShowPanelId - describes whether or not panel ids are to be
shown. This can be CMIC_HIDE_PANEL_ID,
CMIC_SHOW_PANEL_ID, or CMIC_TOGGLE_PANEL_ID,
which do not show the panel id, show the panel
id, or toggle the showing of the panel id,
respectively.
pszHelpLibraryName - points to a string containing the name of the
file containing the panel definitions.
After initializing the HELPINIT structure, you call the
WinCreateHelpInstance API.
HWND APIENTRY WinCreateHelpInstance(HAB hab,
PHELPINIT phinitHMInitStructure);
This returns the window handle of the Help Manager instance, to which you
can send messages. Even though this might not be NULL, indicating
success, you should still check the ulReturnCode field of the HELPINIT
structure for any warnings that are returned.
After the frame window is created, you call the WinAssociateHelpInstance
API. The need for this is described later.
BOOL APIENTRY WinAssociateHelpInstance(HWND hwndHelpInstance,
HWND hwndApp);
Finally, after the frame is destroyed, you call the
WinDestroyHelpInstance API.
BOOL APIENTRY WinDestroyHelpInstance(HWND hwndHelpInstance);
Message handling is simple, since it is done in the standard way.
Although there are many messages defined, the few that you will typically
use are listed below.
The following messages are sent to the Help Manager and take no
parameters, unless otherwise specified:
HM_DISPLAY_HELP - tells the Help Manager to display a help
panel. PVOIDFROMMP(mp1) should point to a
panel name or contain a panel id.
SHORT1FROMMP(mp2) describes what mp1 contains:
HM_RESOURCEID - SHORT1FROMMP(mp1) is the
panel id
HM_PANELNAME - PVOIDFROMMP(mp1) points to
the panel name
HM_EXT_HELP - tells the Help Manager to display the extended
help panel for the window
HM_HELP_CONTENTS - tells the Help Manager to display the table of
contents
HM_HELP_INDEX - tells the Help Manager to display the index
HM_KEYS_HELP - tells the Help Manager to display the keys
help panel for the window
The following messages are sent by the Help Manager:
HM_ERROR - indicates an error occurred when viewing help.
LONGFROMMP(mp1) indicates the HMERR_* constant
describing the error.
HM_HELPSUBITEM_NOT_FOUND - indicates that a panel was not found when help
was requested. SHORT1FROMMP(mp1) indicates a
HLPM_* constant describing where help was
requested from (a frame, menu, or a window);
SHORT1FROMMP(mp2) indicates the id of the
active frame or dialog; SHORT2FROMMP(mp2)
indicates the id of the window with the focus,
or the menuitem selected when F1 was pressed.
If FALSE is returned, the Help Manager
displays the extended help panel, else no
action is taken.
HM_QUERY_KEYS_HELP - asks the application for the id of the keys
help panel. The application should return the
id.
Additionally, WM_HELP is sent to the window whenever F1 is pressed. This
should normally be passed on to the default procedure for processing. A
caveat to this is when a pushbutton is used on a dialog. When selected
by the user, the panel corresponding to the pushbutton will be displayed,
which is usually an undesirable result. The workaround is to intercept
the WM_HELP message and display the appropriate panel when the button is
pushed. The WM_HELP parameters are exactly like those of WM_COMMAND:
case WM_HELP:
if (SHORT1FROMMP(mp1)==ID_HELP) {
WinSendMsg(hwndHelpMgr,HM_EXT_HELP,0L,0L);
} else {
return WinDefDlgProc(hwnd,usMsg,mp1,mp2);
} /* endif */
break;
Resource Definitions
--------------------
The resources that need to be defined are one or more trees of tables
describing the relationships between help panels and windows in an
application. There are two types of tables: HELPTABLEs and
HELPSUBTABLEs; the former contains HELPITEMs while the latter contains
HELPSUBITEMs.
HELPITEMs are comprised of three elements, in the following order: the
main window id, the associated HELPSUBTABLE id, and the extended help
panel id.
HELPSUBITEMs are comprised of two elements, in the following order: the
child window id and the help panel id. A child window can be either a
control or a menuitem.
An example of this structure is shown below:
HELPTABLE WND_IMAGE
{
HELPITEM WND_IMAGE, SUBHLP_IMAGE, EXTHLP_IMAGE
HELPITEM DLG_INFO, SUBHLP_INFO, EXTHLP_INFO
}
HELPSUBTABLE SUBHLP_IMAGE
{
HELPSUBITEM M_FILE, HLP_M_FILE
HELPSUBITEM M_FILE, HLP_M_FILE
HELPSUBITEM MI_OPEN, HLP_MI_OPEN
HELPSUBITEM MI_SAVE, HLP_MI_SAVE
HELPSUBITEM MI_CLOSE, HLP_MI_CLOSE
HELPSUBITEM M_EDIT, HLP_M_EDIT
HELPSUBITEM MI_CUT, HLP_MI_CUT
HELPSUBITEM MI_COPY, HLP_MI_COPY
HELPSUBITEM MI_PASTE, HLP_MI_PASTE
HELPSUBITEM MI_DELETE, HLP_MI_DELETE
HELPSUBITEM M_IMAGE, HLP_M_IMAGE
HELPSUBITEM MI_PRINT, HLP_MI_PRINT
HELPSUBITEM MI_INFO, HLP_MI_INFO
HELPSUBITEM M_HELP, HLP_M_HELP
HELPSUBITEM MI_HELPFORHELP, HLP_MI_HELPFORHELP
HELPSUBITEM MI_EXTHELP, HLP_MI_EXTHELP
HELPSUBITEM MI_KEYSHELP, HLP_MI_KEYSHELP
HELPSUBITEM MI_HELPINDEX, HLP_MI_HELPINDEX
}
HELPSUBTABLE SUBHLP_INFO
{
HELPSUBITEM PB_CANCEL, HLP_PB_CANCEL
HELPSUBITEM PB_HELP, HLP_PB_HELP
}
Help Panel Definitions
----------------------
Help panels are defined via a GML language that is compiled using the
"Information Presentation Facility Compiler" (IPFC). The tags, described
in the Programming Guide, allow you to display text, display graphics,
create hyperlinks, display footnotes, and a variety of other things.
Because the language is fairly complex, a rigorous treatment is beyond
the scope of this discussion. A brief description of a .IPF file is in
order, however.
The GML language is based upon "tags" - usually a beginning tag and an
ending tag - which describe something. In a not-so-abstract way, this
means that you use tags to create everything from panels to bitmap
inclusions, and everything in between. Tags begin with a colon and end
with a period; additionally, they can have attributes associated with
them.
An .IPF file begins and ends with a :userdoc. and :euserdoc. tag. Panels
are created using the :h1. and :h2. tags ('h' is for "heading"), the
difference between the two being that (by default) :h1. panels are
visible in the table of contents, while :h2. panels are not. Headers
can have a resource id attribute and a name attribute. For example:
:h1 res=256 id='MYPANEL'.A Heading
:p.This is a help panel
...creates a help panel with resource id=256 and having the name
"MYPANEL". The title of the panel comes immediately after the ending
period.
Paragraphs are started with the :p. tag, and have no ending tag.
Finally, emphasis is done via the :hpn. tag, where 'n' is an emphasis
level from 1-9. Experiment with this value to see what it produces. The
emphasis tag has an ending tag :ehpn. where n matches the value on the
beginning tag.
If it isn't already clear, the resource ids of the panels should match
those in the HELPSUBTABLEs. This introduces a limitation of the IPFC
compiler - there is no way to specify constants for the resource ids.
You could use the C preprocessor, but you could encounter problems. For
example:
:h1 res=EXTHELP_MAIN.Extended help for MyApp.
When the Microsoft C preprocessor substitutes 256 for "EXTHELP_MAIN", it
sees a ".E" immediately following and expects a floating point number in
exponential notation ("256.Ex"). When it sees an 'x' instead of a '+' or
'-', it flags it as an error (a workaround to this is to give the panel a
dummy name. Thus, you get ":h1 res=EXTHELP_MAIN id='DUMMY1'.Extended
help for MyApp").
A nice application to write would be a IPFC preprocessor that scans the
IPF file substituting values for the constants representing them that are
defined in a C #include file. But I digress...
"But Why Daddy?"
----------------
The need for the WinAssociateHelpInstance call is not obvious, so why do
we need to call it? The answer to this lies in the manner in which the
Help Manager determines which panel to display when F1 is pressed.
When F1 is pressed, the Help Manager checks to see if the active window
is associated with a particular Help Manager instance. If not, the
parent chain is referenced until the first window with an associated help
manager instance is found (stopping at the window who's parent is the
desktop). If no window in the parent chain is found, the owner chain is
likewise searched and an HM_ERROR is sent to the active window if no
window was found there either.
If an associated window is found, its help subtable is determined and the
id of the window/control with the focus is looked up in the subtable. If
no match is found, a HM_HELPSUBITEM_NOT_FOUND is sent to the application
and is acted on accordingly, or else the panel for the window/control is
displayed.
To sum up, you should call WinAssociateHelpInstance whenever: 1) you
create the main frame window or 2) whenever you display a dialog box due
to a user action. For dialog boxes, you should disassociate the help
instance in the dialog procedure's processing of the WM_DESTROY message,
by calling WinAssociateHelpInstance with the frame window that owns the
dialog.
Summary
-------
In summary, the following things need to be done:
Create a help instance
Associate the help instance after creating the main window
In the window procedure
Trap the WM_COMMANDS for the "Help for help...",
"Extended help...", "Keys help...", and "Help index..."
and send the appropriate HM_* message to display the
requested panel
For every dialog
Associate the help instance with the dialog in WM_INITDLG
Disassociate the help instance in WM_DESTROY
Trap WM_HELP for buttons with BS_HELP style.
Create the HELPTABLEs and HELPSUBTABLEs in the .RC file
Create the help panels.
The code you will write is rather common, and will usually not need to be
modified when using it is various applications, so you can simply copy
the code when writing new applications.