I would like to ask you if you could elaborate a little bit how a C program can work with plugins. One application that I am aware of that does something like that is adripper, where you can add binaries as plugins and then new features are implemented. I bet there are more applications doing something like that.
I guess the main program needs to have some kind of API, which the plugins are using. I am thinking that as soon as the app starts, scans the available plugins, and tries to execute some specific methods (hooks?) and based on the returned information the main app changes the way it works. But I might be totally wrong as well.
Do you guys have any documentation to point me to, so I can check how this is working? What is the best way to develop something like that? Any book to propose on these stuff?
Thank you all for your help.
During my search I found an old article at https://eli.thegreenplace.net/2012/08/24/plugins-in-c that seems to describe a similar implementation like the one I described above.
But I am also interested for your feedback guys, in case you can point me to similar documentation and information.
A basic plugin system is easy to construct by simply using normal
executables as the front end for them. No special API required.
"Hollywood" uses a plugin scheme like this, so does "Pagestream"
the last time I looked some years ago.
To make it work on the many AOS systems, they basically do it in the
most cross-compatible way, that doesn't require special OS features,
just starting up a normal executable where the OS type doesn't matter.
It goes like this;
When the main program is started, it scans the "progdir:plugins" directory,
and for every file it finds, it performs a IDOS->LoadSeg() on it.
The main program then clears its process->pr_Task.tc_UserData field first.
It then starts that loaded seglist code using IDOS->RunCommand() and passes
it a "special" constructed command line string, that would not normally
exist, (eg; like having several ::: colons in it), to identify that it is
being started by the correct main program, the string should also contain
some sort of main program versioning data too.
This "special" string may contain just about anything required, preferably
something you could use IDOS->FindArg() or IDOS->ReadArgs() or friends on
so you don't have to reinvent the wheel and it works back to OS 2.?
The string will arrive into the plugin executable via the _start( args,len )
function arguments. (see; include/dos/startup.h for example.)
If the plugin is satisfied with that string, it just places a pointer to
its private API in pr_Task.tc_UserData and then exits with a "special"
positive integer greater than the RETURN_FAIL value, which is retrieved
in the main program from the IDOS->RunCommand() return value,
otherwise something else appropriate.
If the main program sees this special "success" return code, it looks for
a non-NULL pointer in pr_Task.tc_UserData and stores that internally.
This continues for all plugins.
Upon main program termination, it simply IDOS->UnLoadSeg()'s the stored
seglist pointers that were kept along with the plugin's API vector table
or tag function pointer or whatever you are using internally.
That's basically it... It even works on the 68K versions too.
@cwenzel
Thank you so much for your reply and the details you shared. I will try to experiment a little bit with it and be back to this topic.
@walkero
One disadvantage of the plugin-executable approach is that every plugin use is registered by the AppDir handler. So if your program has, say, 50 plugins, your AppDir: directory will sooner or later contain 50 useless entries, one for each plugin. I personally don't like this.
In my Rave audio editor, plugins are BOOPSI classes. I have developed a private superclass, "pluginmaster.class", which handles common operations such as plugin window creation, GUI opening/closing, preset handling, and audio preview. All plugins are subclasses of pluginmaster.class; they only implement what is specific to them, while the superclass handles the rest.
AmigaOne X5000-020 / 2GB RAM / Sapphire Pulse Radeon RX 560 / AmigaOS 4.1 Final Edition Update 2
Do you have any documentation where someone can find more info on how these are implemented, based on your solution? What should someone look for to do something similar. Because you are right about the AppDir: and the different binaries that will exist in there.
Not really a problem, besides the unlikelyhood he'd have 50 plugins, it's easy to prevent
them appearing in appdir: if that's all you are worried about.
There's a name filter in appdir-handler to thin out the dead wood, just use one of the name
extensions listed in the doc and they won't show up.
@cwenzel
Thanks, good to know!
AmigaOne X5000-020 / 2GB RAM / Sapphire Pulse Radeon RX 560 / AmigaOS 4.1 Final Edition Update 2
I remember using Elf library to load binaries into memory and getting function vectors long time ago. I didn't find my codes to check. Every plugin must implement some functions like Init, End, Render (for the GUI) and some function to share the data with the main program.
It looks like there's quite many ways to do it.
There would be a few ways. No really any OS standard way and it it would be up to each program. However, in the article linked to on top, that uses shared libraries. And that's another way to do it on Amiga, simply as a library, and each required function can be reached as a standard function vector. This way you just need to open it as a library, and the OS will take care of loading the plugin and presenting you with a function base to call functions off. Even having cross CPU support is easy that way,