[Contents] [Index] [Help] [Retrace] [Browse <] [Browse >]

A Hook function must accept the following three parameters in these
specific registers:

    A0  Pointer to the Hook structure.
    A2  Pointer to an object to manipulate.  The object is context
        specific.
    A1  Pointer to a message packet.  This is also context specific.

For a callback function written in C, the parameters should appear in
this order:


myCallbackFunction(Pointer to Hook (A0),
                   Pointer to Object (A2),
                   Pointer to message (A1));


This is because the standard C stub pushes the parameters onto the
stack in the following order: A1, A2, A0.  The following assembly
language routine is a callback stub for C:


    INCLUDE 'exec/types.i'
    INCLUDE 'utility/hooks.i'

    xdef        _hookEntry

    _hookEntry:
        move.l  a1,-(sp)                ; push message packet pointer
        move.l  a2,-(sp)                ; push object pointer
        move.l  a0,-(sp)                ; push hook pointer
        move.l  h_SubEntry(a0),a0       ; fetch actual Hook entry point ...
        jsr     (a0)                    ; and call it
        lea     12(sp),sp               ; fix stack
        rts


If your C compiler supports registerized parameters, your callback
functions can get the parameters directly from the CPU registers
instead of having to use a stub to push them on the stack.  The
following C language routine uses registerized parameters to put
parameters in the right registers.  This routine requires a C compiler
that supports registerized parameters.


    #include <exec/types.h>
    #include <utility/hooks.h>

    #define     ASM     __asm
    #define     REG(x)  register __ ## x

    /* This function converts register-parameter hook calling
     * convention into standard C conventions.  It requires a C
     * compiler that supports registerized parameters, such as
     * SAS/C 5.xx or greater.
     */
    ULONG ASM hookEntry(REG(a0) struct Hook *h, REG(a2) VOID *o, REG(a1) VOID *msg)
    {
        return ((*h->h_SubEntry)(h, o, msg));
    }

A callback function is executed on the context of the module that
invoked it.  This usually means that callback functions cannot call
functions that need to look at environment specific data.  For example,
printf() needs to look at the current process's input and output
stream.  Entities like Intuition have no input and output stream.  The
limitations on a callback function depend heavily upon the subsystem
that is using them.  See that subsystem's documentation for more
information.

For the callback function to access any of its global data, it needs to
make sure the CPU can find the function's data segment.  It does this
by forcing the function to load the offset for the program's data
segment into CPU register A4.  See your compiler documentation for
details.

The following is a simple function that can be used as a callback Hook.


    ULONG MyFunction (struct Hook *h, VOID *o, VOID *msg)
    {
        /* A SASC and Manx function that obtains access to the global data segment */
        geta4();

        /* Debugging function to send a string to the serial port */
        KPrintF("Inside MyFunction()n");

        return (1);
    }

The next step is to initialize the Hook for use.  This basically means
that the fields of the Hook structure must be filled with appropriate
values.

The following simple function initializes a Hook structure.

    /* This simple function is used to initialize a Hook */
    VOID InitHook (struct Hook *h, ULONG (*func)(), VOID *data)
    {
        /* Make sure a pointer was passed */
        if (h)
        {
            /* Fill in the hook fields */
            h->h_Entry = (ULONG (*)()) hookEntry;
            h->h_SubEntry = func;
            h->h_Data = data;
        }
    }

Hooks1.c is a simple example of initializing and using a callback
Hook function.