Jump to content

PMGuide - Hooks: Difference between revisions

From EDM2
Line 329: Line 329:
The ''message control hook'' allows the application to determine the flow of messages to be intercepted. The following code shows the syntax for a message control hook function:
The ''message control hook'' allows the application to determine the flow of messages to be intercepted. The following code shows the syntax for a message control hook function:


<pre>
<pre>
BOOL EXPENTRY MsgControlHook(HAB hab,
BOOL EXPENTRY MsgControlHook(HAB hab,
LONG/SHORT idContext,
LONG/SHORT idContext,
Line 337: Line 337:
LONG/SHORT idControl,
LONG/SHORT idControl,
PBOOL fSuccess);
PBOOL fSuccess);
&lt;/pre>
</pre>


If the hook is unable to alter the message control state, then the hook must establish the relevant error information.
If the hook is unable to alter the message control state, then the hook must establish the relevant error information.

Revision as of 05:00, 28 April 2025

A hook is a point in a system-defined function where an application can supply additional code that the system processes as though it were part of the function. This chapter describes how to use hooks in PM applications.

About Hooks

Many operating system functions provide points where an application can hook in its own code to enhance or override the default processing of the function. Most hooks enable an application to monitor some aspect of the message stream. For example, the input hook enables an application to monitor all messages posted to a particular message queue.

A hook function can be associated with the system-message queue, so that it monitors messages for all applications. These system-queue hook functions can be called in the context of any application. However, they must be defined in separate dynamic link library (DLL) modules, because it is not possible to call application-module procedures from other applications.

A hook function can also be associated with the message queue of an individual thread, so that it monitors messages for that thread only. These message-queue hook functions are called only in the context of the thread. Therefore, these hook functions are typically defined locally.

OS/2 operating system contains many types of hooks, and the system maintains a separate hook list for each type of hook supported.

Hook Lists

A hook list contains the addresses of the functions that the system calls while processing a hook. An application can take advantage of a particular type of hook by defining a hook function and using WinSetHook to enter the address of the function in the corresponding hook list. To specify the hook type in WinSetHook, the application uses one of the following constants:

Constant Name Description
HK_CHECKMSGFILTER Lets applications apply very specific message filtering. See HK_CHECKMSGFILTER - Check Message Filter Hook.
HK_CODEPAGECHANGED Lets applications determine when the code page changes. See HK_CODEPAGECHANGE - Code Page Changed Hook.
HK_DESTROYWINDOW Called whenever a window is destroyed. See HK_DESTROYWINDOW - Destroy Window Hook.
HK_FINDWORD Lets applications control where WinDrawText places line breaks. See HK_FINDWORD - Find Word Hook.
HK_FLUSHBUF Lets applications save data before the system reboots. See HK_FLUSHBUF - Flush Buffer Hook.
HK_HELP Monitors the WM_HELP message. See HK_HELP - Help Hook.
HK_INPUT Monitors messages in the specified message queue. See HK_INPUT - Input Hook.
HK_JOURNALPLAYBACK Lets applications insert messages into the system message queue. See HK_JOURNALPLAYBACK - Journal Playback Hook.
HK_JOURNALRECORD Lets applications record mouse and keyboard input messages. See HK_JOURNALRECORD - Journal Record Hook.
HK_LOADER Lets the library and procedure loading and deleting calls be intercepted. See HK_LOADER - Loader Hook.
HK_LOCKUP Called when the system locks itself up. See HK_LOCKUP - Lockup Hook.
HK_MSGCONTROL Monitors the flow of messages to be intercepted. See HK_MSGCONTROL - Message Control Hook.
HK_MSGFILTER Monitors input events during system modal loops. See HK_MSGFILTER - Message Filter Hook.
HK_MSGINPUT Lets applications simulate user input, and only mouse and keyboard messages should be passed in. All other messages will be discarded. Mouse and keyboard messages injected into this hook will have the same effect as if they were generated by the mouse or keyboard device driver. The messages are routed in the same manner as normal user input. See HK_MSGINPUT - Message Input Hook.
HK_PLIST_ENTRY Called every time a program-list call or initialization file call is invoked by an application. It is called before the call is run. See HK_PLIST_ENTRY - Program List Call Hook.
HK_PLIST_EXIT Called every time a program-list call or initialization file call is invoked by an application. It is called before the call is run. See HK_PLIST_EXIT - Program List Exit Hook.
HK_REGISTERUSERMSG Called whenever a user message or data type is registered. See HK_REGISTERUSERMSG - Register User Message Hook.
HK_SENDMSG Monitors messages sent by using WinSendMsg. See HK_SENDMSG - Send Message Hook.
HK_WINDOWDC Called when a device context is allocated or freed. See HK_WINDOWDC - Device Context Hook.

While running a function that contains a hook, the system checks for any function addresses in the hook list that correspond to the type of hook. If an address is found, the system tries to locate and run the function.

Hook Chains

In the hook lists associated with most message-monitoring hooks, the function addresses are linked to form chains. The system passes a message to each hook function in the list, one after the other. Each function can modify the message or stop its progress through the chain, thereby preventing it from reaching the next hook or the destination window. The system calls chained hook functions in last-installed, first-called order.

Hook Types

Each type of hook passes a characteristic set of arguments to the functions referenced in the corresponding hook list. For an application to use a particular hook, it must define a function that processes those arguments and enter the address of the function in the hook list using WinSetHook. This section describes the types of hooks available in OS/2 operating system and the requirements of the functions that process each hook type.


HK_CHECKMSGFILTER - Check Message Filter Hook

The check message filter hook is called whenever WinGetMsg, WinWaitMsg, or WinPeekMsg are used to filter message identities. This hook lets an application apply very specific message filtering, for example, based on the values of message parameters. This hook is called after window handle filtering and before message filtering. The following code shows the syntax for a check message filter hook function:

BOOL EXPENTRY CheckMsgFilterHook ( HAB  hab,
                                   PQMSG pQmsg,
                                   ULONG usFirst,
                                   ULONG usLast,
                                   ULONG fOptions);

The hab parameter is the anchor block handle. The pQmsg parameter is a pointer to a QMSG data structure that contains information about the message. The usFirst parameter is the first message identity specified on a call to the WinGetMsg, WinPeekMsg, or WinWaitMsg function. The usLast parameter is the last message identity specified on a call to the WinGetMsg, WinPeekMsg, or WinWaitMsg function. The fOptions parameter indicates whether or not the message is removed from the queue:

  • PM_NOREMOVE
  • PM_REMOVE

If the check message filter hook function returns TRUE, the message is accepted by the filtering. Any further check message filter hooks in the chain are ignored, any filtering specified by the WinGetMsg, WinPeekMsg, and WinWaitMsg functions are ignored, and processing of the message continues. A hook that always returns TRUE effectively switches off message filtering. If the check message filter hook function returns FALSE, the message is passed on to the next check message filter hook in the chain. If the end of the chain has been reached, the filtering specified by the WinGetMsg, WinPeekMsg, or WinWaitMsg functions is applied.

HK_CODEPAGECHANGE - Code Page Changed Hook

The code page changed hook notifies an application when the code page associated with the specified message queue has been changed. The system calls a code page changed hook function after setting the new code page. Typically, the code page changed hook is used in applications that support multiple languages. The following code shows the syntax for a code page changed hook function:

VOID EXPENTRY CodePageChangedHook(HMQ hmq,
                                   USHORT usOldCodepage,
                                   USHORT usNewCodepage);

The hmq parameter receives the handle of the message queue that is changing its code page. The usOldCodepage is the code page identifier of the previous code page. The usNewCodepage parameter is the identifier of the new code page. A code page changed hook function does not return a value, and the system always calls the next function in the chain.

HK_DESTROYWINDOW - Destroy Window Hook

The destroy window hook is called whenever a window is destroyed. The following code shows the syntax for a destroy window hook function:

BOOL EXPENTRY DestroyWindowHook (HAB  hab,
                                   HWND  hwnd,
                                   ULONG ulReserved);

This hook is sent after the WM_DESTROY message has been sent and just before the window becomes invalid. The hab parameter is the anchor block handle. The hwnd parameter is the handle of the window being destroyed. The ulReserved parameter is reserved. When this hook function returns TRUE, the function completed successfully. When it returns FALSE, an error occurred.

HK_FINDWORD - Find Word Hook

The find word hook allows an application to control where WinDrawText breaks a character string that is too wide for the drawing rectangle. If the DT_WORDBREAK flag is set, the system calls this hook from within WinDrawText. Typically, this hook is used to avoid awkward line breaks in applications that use double-byte character sets. The following code shows the syntax for a find word hook function:

BOOL EXPENTRY FindWordHook(USHORT usCodepage,
                                   PSZ    pszText,
                                   ULONG  cb,
                                   ULONG  ich,
                                   PULONG pichStart,
                                   PULONG pichEnd,
                                   PULONG pichNext);

The usCodePage parameter contains the code page identifier of the string to be formatted; the pszText parameter contains a pointer to the actual string. The cb parameter contains a value specifying the number of bytes in the string. This value is 0 if the string is null-terminated. The ich parameter contains the index of the character in the string that intersects the right edge of the drawing rectangle. A find word hook function uses these four parameters to determine the word that contains the intersecting character. It then fills the remaining three parameters, pichStart, pichEnd, and pichNext, with the indexes of the starting character of the word, ending character of the word, and starting character of the next word in the string. If the find word hook function returns TRUE, WinDrawText draws the string only up to, but not including, the specified word. If the function returns FALSE, WinDrawText formats the string in the default manner.

HK_FLUSHBUF - Flush Buffer Hook

The flush buffer hook allows applications to save data before the system reboots. The following code shows the syntax for a flush buffer hook function:

BOOL EXPENTRY FlushBufHook (HAB  hab);

This hook is called to notify applications that the system is rebooting due to a Ctrl+Alt+Del sequence being entered. It enables applications to write existing information to the hardfile immediately, avoiding loss of data before the system reboots. Template:Note The hab parameter is the application anchor block. When this function returns TRUE, the function completed successfully. When this function returns FALSE, an error occurred.

HK_HELP - Help Hook

The help hook allows an application to include online help. The system calls a help hook function during the default processing of the WM_HELP message. Help processing is done in two stages: creating the WM_HELP message and calling the help hook. The WM_HELP message can come from the following sources:

  • WM_CHAR message, after translation by an ACCEL data structure with the AF_HELP style. The default system accelerator table translates the F1 key into a help message. The WM_HELP message is posted to the current focus window, which can be a menu, a button, a frame, or your client window.
  • Menu-bar selection, when the MIS_HELP style is specified for the menu-bar item. The WM_HELP message is posted to the current focus window.
  • Dialog-window push button, when the BS_HELP style is specified for the push button. The WM_HELP message is posted to the owner window of the button, which normally is the dialog window.
  • Message box, when the MB_HELP style is specified for the message box. The WM_HELP message is posted to the message box.

The WM_HELP message is posted to the current focus window. The default processing in WinDefWindowProc is to pass the message up to the parent window. If the message reaches the client window, it can be processed there. If the message reaches a frame window, the default frame-window procedure calls the help hook. The help hook is also called if a WM_HELP message is generated while the application is in menu mode, that is, while a selection is being made from a menu. The following code shows the syntax for a help hook function:

BOOL EXPENTRY HelpHook(HAB hab, ULONG usMode, ULONG idTopic,
                                   ULONG idSubTopic, PRECTL prcPosition)

If a help hook function returns TRUE, the system does not call the next help hook function in the chain. If the function returns FALSE, the system calls the next help hook function in the chain. The arguments passed to the function provide contextual information, such as the screen coordinates of the focus window and whether the message originated in a message box or a menu. The WM_HELP message often goes to a frame window instead of to the client window. The frame window processes a WM_HELP message as follows:

  • If the window with the focus is the FID_CLIENT window, the frame window passes the WM_HELP message to the FID_CLIENT window.
  • If the parent of the window with the focus is the FID_CLIENT frame-control window, the frame window calls the help hook, specifying the following:
Mode     = HLPM_FRAME
Topic    = frame-window identifier
Subtopic = focus-window identifier
Position = screen coordinates of focus window
  • If the parent of the focus window is not an FID_CLIENT window (it could be the frame window or a second-level dialog window), the frame window calls the help hook, specifying the following:
Mode     = HLPM_WINDOW
Topic    = identifier of parent of focus window
Subtopic = focus-window identifier
Position = screen coordinates of focus window

An application receives the WM_HELP message in its dialog-window procedure. The application can ignore the message, in which case the frame-window action occurs as described, or the application can handle the WM_HELP message directly. Menu windows receive a WM_HELP message when the user presses the Help accelerator key (F1 by default) while a menu is displayed. Menu windows process WM_HELP messages by calling the help hook, specifying the following:

Mode     = HLPM_MENU
Topic    = identifier of pull-down menu
Subtopic = identifier of selected item in pull-down menu
Position = screen coordinates of selected item

A help hook function should respond by displaying information about the selected menu item. WinDefWindowProc processes WM_HELP messages by passing the message to the parent window. Typically, the message moves up the parent chain until it arrives at a frame window.


HK_INPUT - Input Hook

The input hook enables an application to monitor the system-message queue or an application-message queue. The system calls an input-hook function whenever WinGetMsg or WinPeekMsg is about to return a message. Typically, an application uses the input hook to monitor mouse and keyboard input and other messages posted to a queue. The following code shows the syntax for an input-hook function:

<pre> BOOL EXPENTRY InputHook(HAB hab, PQMSG pQmsg, ULONG fs) </pre>

The pQmsg parameter is a pointer to a QMSG data structure that contains information about the message. The fs parameter of InputHook can contain the following flags from WinPeekMsg, indicating whether or not the message is removed from the queue:

<pre> PM_NOREMOVE PM_REMOVE </pre>

If an input-hook function returns TRUE, the system does not pass the message to the rest of the hook chain or to the application. If the function returns FALSE, the system passes the message to the next hook in the chain or to the application if no other hooks exist. An input-hook function can modify a message by changing the contents of the QMSG data structure, then returning FALSE to pass the modified message to the rest of the chain. The following problems can occur when a hook modifies a message:

   If the caller uses WinPeekMsg or WinGetMsg with a message filter range (msgFilterFirst through msgFilterLast), the message is checked before the hook functions are called, not after. If the input-hook function modifies the msg field of the QMSG data structure, the caller can receive messages that are not in the range of the message filter of the caller.
   If the input-hook function changes a WM_CHAR message from one character into another—for example, if the function modifies all Tab messages into F6 messages—an application that depends on the key state is unable to interpret the result. (When the Tab key is translated into the F6 key, the application receives the F6 keystroke and enters a process loop, waiting for the F6 key to be released; the application calls WinGetKeyState with the HWND_DESKTOP and VK_F6 arguments).

HK_JOURNALPLAYBACK - Journal Playback Hook

The journal playback hook enables an application to insert messages into the system-message queue. Typically, an application uses this hook to play back a series of mouse and keyboard events that were recorded earlier using the journal record hook. A journal playback hook function can be associated only with the system-message queue. Regular mouse and keyboard input is disabled as long as a journal playback hook is installed. It is important to notice that, because mouse and keyboard input are disabled, this hook can easily hang the system. The following code shows the syntax for a journal playback hook function:

<pre> ULONG EXPENTRY JournalPlaybackHook(HAB hab, BOOL fSkip, PQMSG pQmsg) </pre>

The pQmsg parameter is a pointer to a QMSG data structure that the journal playback hook function fills in with the message to be played back. If the fSkip parameter is FALSE, the function fills in the QMSG data structure with the current recorded message. The function returns the same message each time it is called, until fSkip is TRUE. The same message is returned many times if an application is examining the queue but not removing the message. If fSkip is TRUE, the function advances to the next message without filling in the QMSG data structure, because the pQmsg parameter is NULL when fSkip is TRUE. The journal playback hook returns a ULONG time-out value that tells the system how many milliseconds to wait before processing the current message from the playback hook. This enables the hook to control the timing of the events it plays back. The time field of the QMSG data structure is filled in with the current time before the playback hook is called. The hook should use the time stored in this field, instead of the system clock, to set up delays between events.

HK_JOURNALRECORD - Journal Record Hook

The journal record hook allows an application to monitor the system-message queue and to record input events. Typically, an application uses this hook to record a sequence of mouse and keyboard events that it can play back later by using the journal playback hook. A journal record hook function can be associated only with the system-message queue. The following code shows the syntax for a journal record hook function:

<pre> VOID EXPENTRY JournalRecordHook(HAB hab, PQMSG pQmsg) </pre>

The pQmsg parameter is a pointer to a QMSG data structure containing information about the message. The system calls the journal record hook function after processing the raw input enough to create valid WM_CHAR or mouse messages and after setting the window-handle field of the QMSG data structure. A journal record hook function does not return a value, and the system always calls the next function in the chain. Typically, a journal record hook function saves the input events to a disk file to be played back later. The hwnd field of the QMSG data structure is not important and is ignored when the message is played back. The following messages are passed to the journal record hook:

<pre> WM_CHAR WM_BUTTON1DOWN WM_BUTTON1UP WM_BUTTON2DOWN WM_BUTTON2UP WM_BUTTON3DOWN WM_BUTTON3UP WM_MOUSEMOVE. </pre>

The positions stored in the mouse messages are in screen coordinates. The system does not combine mouse clicks into double clicks before calling the hook, because there is no guarantee that both clicks will be in the same window when they are played back. The system passes a WM_JOURNALNOTIFY message to the journal record hook function whenever an application calls WinGetPhysKeyState or WinQueryQueueStatus. This message is necessary because the system-message queue is only one message deep while a playback hook is active. For example, the user might press the A, B, and C keys while in record mode. While the application is processing the A character message, the B key might be down; WinGetPhysKeyState returns this information. However, during playback mode, the system knows only that it currently is processing the A key.

HK_LOADER - Loader Hook

The loader hook allows the library and procedure loading and deleting calls to be intercepted. The following code shows the syntax for a loader hook function:

<pre> BOOL EXPENTRY LoaderHook(HAB hab, LONG idContext, PSZ pszLibname, PHLIB hlib, PSZ pszProcname, PFNWP wndProc); </pre>

If the hook attempts a load or deletion which is unsuccessful, then the hook must establish the relevant error information. The hab parameter is the anchor block handle. The idContext parameter is the origin of the call to the hook:

   LHK_DELETEPROC WinDeleteProcedure
   LHK_DELETELIB WinDeleteLibrary
   LHK_LOADPROC WinLoadProcedure
   LHK_LOADLIB WinLoadLibrary

The pszLibname parameter is the library name. The hlib parameter is a pointer to a library handle. If the idContext parameter is set to LHK_LOADLIB, then this hook must set the value of this parameter to the handle of the loaded library or to NULLHANDLE if the load fails. The pszProcname parameter is the procedure name. The wndProc parameter is the window procedure identifier. If the idContext parameter is set LHK_LOADPROC, then this hook must set the value of this parameter to the handle of the loaded procedure or to NULL if the load fails. The pfSuccess parameter is the success indicator, which is either TRUE or FALSE. If it is TRUE, the library or procedure loaded or deleted successfully. If it is FALSE, the library or procedure not loaded or deleted successfully. When this function returns TRUE, it does not call the next hook in chain. When this function returns FALSE, then it does call the next hook in chain.

HK_LOCKUP - Lockup Hook

The lockup hook is called when the system locks itself up. The following code shows the syntax for a lockup hook function:

<pre> BOOL EXPENTRY LockupHook (HAB hab, HWND hwndLockupFrame); </pre>

The hab parameter is the application anchor block. The hwndLockupFrame parameter is the frame window of the lockup panel. This function has no return value. All HK_LOCKUP hooks registered with the system are called when the system locks itself up. All HK_LOCKUP hooks must be system hooks, not message queue hooks. Application programs that create other lockup password input windows by hooking the HK_LOCKUP system hook can use WinUnlockSystem to force the system to unlock when another form of input is detected other than mouse or keyboard. For example, a pen gesture or some voice input or signature recognition.

HK_MSGCONTROL - Message Control Hook

The message control hook allows the application to determine the flow of messages to be intercepted. The following code shows the syntax for a message control hook function:

BOOL EXPENTRY MsgControlHook(HAB hab,
LONG/SHORT idContext,
HWND hwnd,
PSZ pszClassname,
ULONG/USHORT usMsgclass,
LONG/SHORT idControl,
PBOOL fSuccess);

If the hook is unable to alter the message control state, then the hook must establish the relevant error information. The hab parameter is the anchor block handle. The idContext parameter is the origin of the call to the hook and has one of the following values:

   MCHK_CLASSMSGINTEREST WinSetClassMsgInterest
   MCHK_MSGINTEREST WinSetMsgInterest
   MCHK_MSGMODE WinSetMsgMode
   MCHK_SYNCHRONISATION WinSetSynchroMode   

The hwnd parameter is the window handle. The pszClassName parameter is the window class name. The usMsgClass parameter is the message class. The idControl parameter is the control setting. The fSuccess parameter is the success indicator and is either TRUE (success) or FALSE (error). This function returns either TRUE or FALSE. If it returns TRUE, the next hook in the chain is not called. If it returns FALSE, the next hook in the chain is called.

HK_MSGFILTER - Message Filter Hook

The message-filter hook allows an application to provide input filtering (such as monitoring hot keys) during system-modal loops. The system calls a message-filter hook function while tracking the window size and movement, displaying a modal dialog window or message box, tracking a scroll bar, and during window-enumeration operations. The following code shows the syntax for a message-filter hook function:

BOOL EXPENTRY MsgFilterHook(HAB hab, PQMSG pQmsg, ULONG msgf)

The msgf parameter can have one of the three values shown in the following table:

Parameter Value Description
MSGF_DIALOGBOX Message originated while processing a modal dialog window or a message box.
MSGF_MESSAGEBOX Message originated while processing a message box.
MSGF_TRACK Message originated while tracking a control (such as a scroll bar).

The pQmsg parameter of MsgFilterHook is a pointer to a QMSG data structure containing information about the message. If a message-filter hook function returns TRUE, the system does not pass the message to the rest of the hook chain or to the application. If the function returns FALSE, the system passes the message to the next hook function in the chain or to the application if no other functions exist. This hook enables applications to perform message filtering during modal loops that is equivalent to the typical filtering for the main message loop. For example, applications often examine a new message in the main event loop between the time they retrieve the message from the queue and the time they dispatch it, performing special processing as appropriate. An application usually cannot do this sort of filtering during a modal loop, because the system runs the loop created by WinGetMsg and WinDispatchMsg. If an application installs a message-filter hook function, the system calls the function between WinGetMsg and WinDispatchMsg in the modal processing loop. An application can also call the message-filter hook function directly by calling WinCallMsgFilter. With this function, the application can use the same code as the main message loop to filter messages during modal loops. To do so, the application encapsulates the filtering operations in a message-filter hook function and calls WinCallMsgFilter between WinGetMsg and WinDispatchMsg calls, as shown in the following code fragment:

while (WinGetMsg(hab, (PQMSG) &qmsg, (HWND) NULL, 0, 0))
{
if (!WinCallMsgFilter(hab, (PQMSG) &qmsg, 0))
WinDispatchMsg(hab, (PQMSG) &qmsg);
}

The last argument of WinCallMsgFilter is passed to the hook function; the application can enter any value. By defining a constant such as MSGF_MAINLOOP, the hook function can use that value to determine from where the function was called.