Blitz (60/193)

From:David McMinn
Date:11 Aug 2000 at 11:26:23
Subject:Re: SDS TCP/IP Library and HOOKS

Hi Davide

Sorry for the long reply, but you asked for it :)

> I would like to know how to make an hook !!! Everyone write their own
> hook for list and for other thing...
>
> I don't know (in 1st place) what an hook is exactly !! and second I
> don't know how to start with it...

A hook is simply a function that you have written to extend the abilities of an
OS function, combined with a Hook newtype which contains information about
calling the hook function.

Normally, you pass the address of the Hook newtype in a TagList (do you know
about TagLists?) to the OS function and your function will get called by the OS
function.

In the Hook newtype you'll find something like this:

NEWTYPE Hook
h_MinNode.MinNode

END NEWTYPE

You don't really need to bother about the h_MinNode field.

The h_Entry field is the address of the routine which gets called by the OS
function. Parameters are passed to this routine in the following registers:
a0 - pointer to the Hook newtype itself
a1 - pointer to parameter structure ("message").
a2 - Hook specific address data ("object").
The use of those last two depend on what OS function you are extending.

Obviously, because we are using a high level language, we want to write our
hook function in Blitz. The standard way of having the parameters layed out in
the high level language function is:
Function{Hook, object, message}
Note the order of parameters - NOT in order a0,a1,a2! This gives us a problem
since Blitz functions cannot take parameters in address registers. This is what
the h_SubEntry field is for. You make the h_SubEntry field point to the high
level language function you have written as the hook function. You then make
the h_Entry field point to a small assembly language routine which puts the
parameters in the correct place and calls the routine pointed to by the
h_SubEntry field.

The h_Data field is for user use and can be anything you want, for example if
you needed to pass extra data structures to the hook function you could set up
a pointer to those here.

There are additional problems using hook functions in Blitz. One is that you
cannot be guarunteed about the contents of the address register that is used to
access your global variables (a5). This means that you must store it somewhere
before calling any hooks, and restore it before you call the Blitz function.
Another is that the Blitz debugger does not like being used inside functions
which have been called from a hook, so you need to put RunErrsOff....RunErrsOn
around the function.

A piece of assembly language which you can use to put the parameters in the
correct order and call the Blitz function is this (this is what you would make
the h_Entry field point to):

_hookEntry:
movem.l d2/a5,-(a7) ; Preserve non-scratch registers we alter
move.l a1,d2 ; Make the message the third parameter
move.l a2,d1 ; The object is the second parameter
move.l a0,d0 ; The hook is the first parameter
move.l globalbase(pc),a5 ; restore our global variable base
move.l 12(a0),a0 ; get pointer to high level language function
jsr 6(a0) ; call the high level language function
movem.l (a7)+,d2/a5 ; Restore non-scratch registers we altered
rts
globalbase: Ds.l 1 ; Some space for preserving global variable base

(Scratch registers on the Amiga are registers that have been designated as
registers that can have their contents changed when calling functions, and are
not guarunteed to be restored after the function. These registers are d0, d1,
a0 and a1. This means we can change them and not need to preserve them since
the piece of code that called our routine should not assume that the contents
of these register will be the same when we are finished.)

You will be able to use that piece of assembly language for all the h_Entry
field of all your hooks.

To set up a Hook newtype, you can write some code like this:

DEFTYPE.Hook myhook ; Define the Hook variable
myhook\h_Entry = ?_hookEntry ; Make h_Entry point to the ASM routine above
myhook\h_SubEntry = ?hookfunc ; Make h_SubEntry point to the Blitz function
; we want to use as the hook function
myhook\h_Data = $DEADBEEF ; This can be anything you want

At the top of your program somewhere you would need to put this line (so that
the global variable base register is preserved):

move.l a5,globalbase

Finally, you have your Blitz function which you are using as the hook function:

RunErrsOff
hookfunc: ; This is the label that you use in the h_SubEntry field
; as shown above
Function.l MyHookFunc{*hook.Hook, *object.l, *message.l}
; You can of course make the object and message parameters have any type
; you want, so that they are more easily used.

; Obviously you would do whatever you need in here. Any value that you
; return from this function will be the value returned to the OS function
; by the hook.
End Function
RunErrsOn

Then, when you call the OS function you are extending, it will normally have a
tag that you can specify a hook for. You would do that by passing the address
of the myhook variable in this example (using &myhook).

If you want more than one hook in a program, the easiest think to do is set up
a few Hook newtype variables and give them all the same h_Entry (the one above
should be OK for all) and then a different h_SubEntry, calling the appropriate
function.

The example I put on Aminet (using the ASL screen mode requester) is slightly
wrong, in that it does not use the parameters for the Blitz function in the
standard order as I have described in this email, above. However all the rest
is pretty much the same.



|) /\ \/ ][ |) |\/| c |\/| ][ |\| |\| | dave@satanicdreams.com
http://members.xoom.com/David_McMinn | ICQ=16827694
'Bother', said Pooh as he realised he was eating from the furry honeypot

---------------------------------------------------------------------
To unsubscribe, e-mail: blitz-list-unsubscribe@netsoc.ucd.ie
For additional commands, e-mail: blitz-list-help@netsoc.ucd.ie