tags:

views:

819

answers:

3
+7  Q: 

Plugin API design

So I have an application that is based heavily on the QT API which using the QPlugin system. It's fairly simple to use, you define a class which inherit from an Interface and when the plugin is loaded you get an instance of that class. In the end it'll boil down to a dlopen/dlsym or LoadLibrary/GetProcAddress, whatever is appropriate for the OS. I have no problems here everything works as expected.

So, onto the issue. There is a lot of functionality that involves a plugin needing to refer to data/functions provided by the main application. For example, my application has a GUI, so I have in my application a "plugin::v1::gui" function which returns a QWidget *. If I want a plugin to be able to add things to my UI, or even make it's dialog a child of my UI it'll need a pointer to it.

I started development on Linux and quickly encountered the fact that by default the loader doesn't fill in unresolved symbols in shared objects with the ones from the application loading it. No problem, easy fix. add "-rdynamic" to my flags and move on. Thing work well.

Now I've discovered that there doesn't appear to be an equivalent on Windows :(. So what is a good solution?

So far the best I've come up with is having a structure I fill up in my main application that has pointers to every object/function a plugin might care about. Then passing that to the plugin's "init" function and now it has proper pointers to everything, but it's an annoying solution since now I have to make changes in multiple places whenever I add something.

Is there a better solution? How has the SO community dealt with this?

A: 

Create a registry object that is passed to the plugin in the initialization function that contains a dictionary of exposed components. Then allow the plugin to request a pointer to components by string name or other identifier from this registry. It sacrifices compile-time type safety for a stable interface.

There are also more heavy-weight solutions like CORBA...

Judge Maygarden
That is mostly *identical* to my "so far the best i've come up with..." sentence. only real difference is whether they request by structure element or by a string passing. I'll take the structure over that due to type safety.
Evan Teran
I can't imagine any other solution to the problem. what do you thought about Evan?
Johannes Schaub - litb
Unfortunately, so far I've found nothing that is really superior. Linux's -rdynamic really would have been nice to stick with. I've started to convert my plugin API to a structure passed, and it's *really* time consuming to get right.
Evan Teran
A: 

You've done that in a relatively good way. Helper-Classes are often the pure way for (only) INSERTING new functionality. If you freshly design your software you have to mention that not every plugin should get access to your administrative structure. So there should be differences in plugin-design.

One possibility: Create some abstract classes which you inherit from, that come with functionality to set your required pointers to Widgets or so.

Other possibility: Expand your main(parent) classes with functions of getParent().getMainWidget(), getParent().getConfigWidget() ....


If it is only about dynamically loading UIs from your UI-Plugin without using pointers, you can do it as on this page described: http://dolzhenko.blogspot.com/2008/10/qt4-dynamic-loading-ui-from-other-ui_07.html

It is done with ui-Files you can access over your main config-Files or whatever.

joki
+1  A: 

Create a set of interfaces for the main interaction objects that will be exposed by your application and build them in a lib/dll of their own and implement those interfaces on classes in your application as appropriate. The library should also include a plugin interface with perhaps just an "initialize" method that the plugin object will implement.

The application and plugin will obviously link against that DLL and once the plugin is loaded by the application the application should call the plugin's initialize method which will have parameters to accept any objects needed to control the application.

A popular way of making this simple is to implement a hierarchy similar to the DOM in your application so that the plugin can get to all the relevant objects in your application from one root object.

joshperry
Here is a good article that explains in detail how to accomplish plugins in this manner: http://www.nuclex.org/articles/building-a-better-plugin-architecture#comment-738
joshperry