In my migration efforts I am now trying to understand how to rewrite the hooks in order to be compliant with OS4 (notably using CallHookPkt) The Migration guide gives information that is probably sufficient for an experienced programmer, but not for me.
I don't find an example or a hook in the SDK/examples drawer. Could somebody point me to an example source?
The "hook" parameter is a pointer to the hook that you set up earlier (more on that below).
The "o" parameter usually referes to an object (usually the parent), but you can ignore this for your own hooks. You can alternatively use it to pass your own data strtucture.
The last parameter can be pretty much whatever you want it to be, you pass this pointer from CallHookPkt(), so you can pass some data structure that your hook needs.
You must only change the purpose of hook parameters if you are sure that you will only ever be calling your own hooks. System hooks will expect each parameter to be a certain type, and changing it will obviously lead to problems.
In order to set up the hook, you need a section of code like:
This is usually done in main() or some other high level function so that the "myhook" variable is valid for the life of the program.
You may have noticed that when setting up the hook, there is a "mydatapointer" variable passed in as the h_Data field. Again, this can be anything you like, I personally use it to pass the hook a pointer to my globaldata structure, this way the hook can access anything within the program.
Now, we have the hook set up, and ready to go, we need to call it. CallHookPkt( myhook, NULL, somedata ) will run the code in the hook. The supplied data can be accessed from within the hook like so:
uint32 myhookfunc( struct Hook *hook, Object *o, APTR myhookdata ) { /* my hookdatat is the "somedata" pointer sent by CallHookPkt */ }
Remember the "mydatapointer" we passed in the AllocSysObject() call? Well, we can get that from inside the hook by using:
hookdata = hook->h_Data;
So now the hook has access to globaldata which is constant for the life of the hook, and we can access the "somedata" pointer which is specific to each call of the hook. This gives us two sets of data, one constant, and one which may change depending on the context the hook was called in (ie: You set the "somedata" pointer when you call the hook).
Hooks are very powerfull, but you must be carefull if you are going to change any data from a hook run by an asynchronous process. This may lead to two instances of the hook trying to change data at the same time. Under normal circumstances hooks are synchronous with the program so there is no problem unless you spawn processes which call the same hook. In this case, you should protect the data with a call to (Attempt)ObtainSemaphore(), but again, this can lead to deadlocks with multiple processes trying to obtain the same semaphore as it will be put to sleep while it waits for the semaphore. Also check out the mutex functions for protecting memory regions.
Anyway, I'm confusing you, have a go with the above information, and if you get into problems, ring technical support :)
You might want to use the SDI headers. This will not just ensure compatibility with future releases of OS4, but you automatically get working hooks with OS3, MOS and AROS. The biggest advantage for OS3 compatibility is the fact, that you don't have to crack your head which parameter belongs into which 68k register.
HOOKPROTO(function name, return type, object spec, param spec) { // your function // the hook itself can always be accessed via the passed in variable called "hook" }
If your hook function doesn't need the object and/or param parameters you can just omit them by using the appropriate macro:
HOOKPROTONONP(function name, return type) { // your function // "NO" means "no object" // "NP" means "no param" }
In case you want to compile your program not just for OS4 but for all possible target platforms you cannot make use of the AllocSysObject() call but have to create the struct Hook variables yourself. Even here the SDI macros make your life very simple and easy:
MakeHook(hook name, function name)
That's all to create a global accessible hook. MakeStaticHook() does exactly the same, except that the hook is static to one single source module.
Which ever method you use, just remember that the more abstraction you use, the slower it will get. Hooks invariably are used in loops, so speed is of the essence, inside the hook and in its interface.
Using the SDI headers doesn't make things slower than doing the dirty work yourself. You just don't need to crack your head about the ugly details. Even better, the resulting binary will be the same, no matter which solution you choose. But the biggest advantage is the common "API" for different platforms: OS3, OS4, MOS and AROS, all covered under a uniform hood.
The speed thing just depends on the individual implementation of the hook function, but this is completely independend of how you define the prototype for the hook function. If you spend a million loop iterations inside the hook function this has nothing to do with the SDI headers.
Well, considering the topic is "OS4" hooks, I fail to see why an abstracton such as SDI is required. The hook interface in OS4 is hardly rocket science.
Of course, if the intended outcome is to support other platforms too, then your suggestion makes sense.
For code intended for AmigaOS 4.x I recommend against using the SDI headers because you just end up with yet more name pollution.
Even if your code is intended for multiple platforms, a good design should be factoring out the platform dependent code into independent source modules and not sprinkling macros all over the place IMHO.
I find SDI headers simpler in sintax for hook than each "native" solution (OS3, OS4, MOS and AROS), so it's a good start point for which wants convert/port/begin.
@Rigo and others: Rght now i want to understand fully the OS4 way of doing things and have an OS4 source up and running. I did have a look at the SDI headers and right now it is a complementary source of confusion in my situation.
The hook concerned is a custom stringgadget hook.
After much labour investigating available documentation, headers and autodocs and the source ( which i did not develop ) my main question remains the CallHookPkt function: I don't know where to insert it. I don't find anything similar in the OS3 source.
I understand there are three things to do - write a Hook function, this function exists and i think it will do (no errors) <ULONG INTERRUPT SAVEDS TextInHook(struct Hook *hook, struct SGWork *sgw, ULONG *msg)>
- Use AllocSysObject: i think i found the line to change in ttne InitGadgets function InitHook (&tid->hk, TextInHook, bt); will become &tid->hk=AllocSysObject( ASOT_HOOK, ASOHOOK_Entry, func, ASOHOOK_Data, bt, TAG_DONE) -lastly insert CallHookPkt( &tid->hk, NULL, somemsg ) but where?
I understand the somemsg info will then be given as third argument to TextInHook/ As i don't see an equivalent to CallHookPkt in the source i am also in doubt which second argument i should use in CallHookPkt
I don't know what you are trying to do exactly but if you are for example trying to setup a Hook the stringgadget is supposed to use, then that's not your job to CallHookPkt() it will be done by the stringgadget itself when needed. For this you have to tell the stringgadget you have written a hook function for it, generally you either do it at stringgadget object creation, either at runtime using a SetAttrs() on one of its attribute, for example let's say you want to install an EditHook you'll write something like
PS: BTW your code with AllocSysObject won't work because as its name implies AllocSysObject *is* allocating the object, while it seems in your code the variable hk in the object tid is of type struct Hook rather than struct Hook *, which means it statically allocated at tid's creation. You should change its definition to struct Hook * and remove any '&' in front of tid->hk from the source but that should be no problem if you are familiar with C pointers and C in generall...
I had a hell of a lot of time to remove some error "expected something at end of input." The missing brace was not in the the file the error pointed to (containing main() but in some other file included. I also will from now on disapprove using the /* */ pair for just some line comment.
I also had to use AllocSysObjectTags since using __USE_INLINE__ makes the compiler think you are working with a macro with two arguments.
} I derived theis from analogy with teh TextINHool (gadget string hook above. and from the original 68 k source.
What i don't understand is how the bfd are uused or found . I don't even find in the source where its values are set. Does the do_backfil() hook function follows some template known to the system? If yes where is this described?
I find SDI headers simpler in sintax for hook than each "native" solution (OS3, OS4, MOS and AROS), so it's a good start point for which wants convert/port/begin.
I second that. For years, I used SDI headers that make hooks really simple to use and the source is readable and it supports all systems. They perfectly fill my needs.
For code intended for AmigaOS 4.x I recommend against using the SDI headers because you just end up with yet more name pollution.
I noticed this thread when I was about to open a topic asking about hooks. I simply wanted to add a hook to a system function and found the autodocs somewhat confusing. Intuition and WorkBench show examples assigning hookEntry to the function HookEntry() in amiga_lib and hookSubEnty to the actual hook that is added. Some OS4 examples I found elsewhere assign the actual hook to hookEntry. Can someone explain what that's all about.
IIRC in pre OS4 teh OS wasn't able to directly jump to Hook address and execute the code (I think it was about argument passing, but not really sure) instead you had to jump to a helper function that would then jump to the desired address. So you were putting address of amigalib's HookEntry() into hookEntry and your actual hook into hookSubEntry now this is not needed anymore you only have to put your hook into hookEntry AOS 4 will handle everything for you (be it PPC or 68k code) when called via CallHookPkt()
For 680x0 hook functions the parameters are passed in registers a0, a2 and a1 but in 680x0 C ABI all parameters are passed on the stack.
HookEntry is simply a small assembler stub function that pushes the parameters passed in a0, a2 and a1 onto the stack and then calls the C function in h_SubEntry.
Some C compilers allow to specify that function parameters are passed in registers instead of on the stack. In this case you don't need to use the HookEntry function but can put your function pointer directly in h_Entry. Like in GCC f.e. you could define your hook function like:
Hello, i could solve the first problem , a string gadget hook, with the help you provided, especially that there was no need for the use of CallHookPkt since the call was done by giving the string gadget the appropriate hooktag.
I had to jump into the water though not understanding really what i was doing. I changed the soutce as folows
I commented out the functions hookEntry and InitHook belw
A. The textinhook works ok as described One thing i don't understand is that TextInhook requires apart from the hook two other arguments, and in the initialisation only one is given (bt) So i am guessing that the first struct SGWork is created during the initialisation and the second is passed as bt
I can only understand this if a TextinHook function has a template where the two first arguments are of types struct Hook and struct SGW
I would expect then to find this template in the SDK, but i don't find it.
B. The backfillhook does not work and i probably mixed up some pointerbusyness Here however the 68k initialisation InitHook apart from the hook and the hookfunction has no additional argument (NULL) whereas the do_backfill hook function needs apart from the rastport, which i suppose the initialisation will provide, also a struct BackFillData that does not seem to be system type. How is the do_backfill function provided with this argument? (Or how iscould it be created during the hook initialisation,?)
I am not doubting yet that the 68k InitHook initialisation is wrong, since this source used to compile well for 68k
Clarification of the above would help mme greatly;
A) The gadtools autodocs says that GTST_EditHook will be copied to the StringExtend->EditHook field. If you now make a quick search in the includes you will find the file intuition/sghooks.h. Have you read it?
B) A WA_BackFill hook is, as the autodoc says, a LayerHook that is described in Layers.doc InstallLayerHook() as
I do understand the Backfiil hook now that does not work yet,
I do not fully understand the GTST Edithook, but it worked, i just wantrd to compare both.
>A) >The gadtools autodocs says that GTST_EditHook will be copied to the StringExtend->EditHook >field.
I read this which is far less clear "========================================== GTST_EditHook (struct Hook *) - Hook to use as a custom string gadget edit hook (StringExtend->EditHook) for this gadget. GadTools will allocate the StringExtend->WorkBuffer for you. (defaults to NULL) "==========================================
>If you now make a quick search in the includes you will find the file intuition/sghooks.h. Have >you read it? I find the stuff below, however this does not tell me how my hookfunction gets its SGW argument. ??
"===================================
struct StringExtend { /* display specifications */ struct TextFont *Font; /* must be an open Font (not TextAttr) */ UBYTE Pens[2]; /* color of text/backgroun */ UBYTE ActivePens[2]; /* colors when gadget is active */
/* edit specifications */ ULONG InitialModes; /* initial mode flags, below */ struct Hook *EditHook; /* if non-NULL, must supply WorkBuffer */ STRPTR WorkBuffer; /* must be as large as StringInfo.Buffer*/
ULONG Reserved[4]; /* set to 0 */ };
struct SGWork { /* set up when gadget is first activated */ struct Gadget *Gadget; /* the contestant itself */ struct StringInfo *StringInfo; /* easy access to sinfo */ STRPTR WorkBuffer; /* intuition's planned result */ STRPTR PrevBuffer; /* what was there before */ ULONG Modes; /* current mode */
/* modified for each input event */ struct InputEvent *IEvent; /* actual event: do not change */ UWORD Code; /* character code, if one byte */ WORD BufferPos; /* cursor position */ WORD NumChars; ULONG Actions; /* what Intuition will do */ LONG LongInt; /* temp storage for longint */
struct GadgetInfo *GadgetInfo; /* see cghooks.h */ UWORD EditOp; /* from constants below */ }; ========================================
B) >A WA_BackFill hook is, as the autodoc says, a LayerHook that is described in Layers.doc >InstallLayerHook() as
>BTW: The InstallLayerHook() autodocs needs a update, it still has a 68k-asm example.
I found this ====================== /* * The message a backfill hook receives */ struct BackFillMessage { struct Layer *Layer; struct Rectangle Bounds; LONG OffsetX; LONG OffsetY; }; =======================