From: http://www.devbean.net/2012/03/building-your-own-plugin-framework-2/
Plug-in programming interface
The so-called plug-in is actually an interface-based design. The most basic point of a plug-in-based system is to have a central system to load unknown plug-ins and be able to interact with these plug-ins using predefined interfaces and protocols.
The most basic way is to define an interface and provide a series of functions to be exposed by plug-ins (dynamic or static. This implementation is technically feasible, but it is not so simple. The reason is that a plug-in must support two types of interfaces, but only the function set of one interface can be exposed. This means that the two types of interfaces must be combined.
The first interface (Protocol) is a general plug-in interface. This interface allows the central system initialization plug-in to register the functions provided by the plug-in for object creation and destruction to the central system. This general plug-in interface is not related to specific fields, so it can be used as a reusable library. The second interface is the functional interface provided by the plug-in object. This interface is related to a specific domain and must be carefully designed and implemented by the plug-in. The central system should use this interface to interact with the plug-in object.
Next we will provide a general plug-in interface header file. Here, we will not go into details, just to have a relatively intuitive understanding.
1 #ifndef PF_PLUGIN_H 2 #define PF_PLUGIN_H 3 4 #include <apr-1/apr_general.h> 5 6 #ifdef __cplusplus 7 extern "C" { 8 #endif 9 10 typedef enum PF_ProgrammingLanguage11 {12 PF_ProgrammingLanguage_C,13 PF_ProgrammingLanguage_CPP,14 } PF_ProgrammingLanguage;15 16 struct PF_PlatformServices_;17 18 typedef struct PF_ObjectParams19 {20 const apr_byte_t * objectType;21 const struct PF_PlatformServices_ * platformServices;22 } PF_ObjectParams;23 24 typedef struct PF_PluginAPI_Version25 {26 apr_int32_t major;27 apr_int32_t minor;28 } PF_PluginAPI_Version;29 30 typedef void * (*PF_CreateFunc)(PF_ObjectParams *);31 32 typedef apr_int32_t (*PF_DestroyFunc)(void *);33 34 typedef struct PF_RegisterParams35 {36 PF_PluginAPI_Version version;37 PF_CreateFunc createFunc;38 PF_DestroyFunc destroyFunc;39 PF_ProgrammingLanguage programmingLanguage;40 } PF_RegisterParams;41 42 typedef apr_int32_t (*PF_RegisterFunc)(const apr_byte_t * nodeType,43 const PF_RegisterParams * params);44 45 typedef apr_int32_t (*PF_InvokeServiceFunc)(const apr_byte_t * serviceName,46 void * serviceParams);47 48 typedef struct PF_PlatformServices49 {50 PF_PluginAPI_Version version;51 PF_RegisterFunc registerObject;52 PF_InvokeServiceFunc invokeService;53 } PF_PlatformServices;54 55 typedef apr_int32_t (*PF_ExitFunc)();56 57 typedef PF_ExitFunc (*PF_InitFunc)(const PF_PlatformServices *);58 59 #ifndef PLUGIN_API60 #ifdef WIN3261 #define PLUGIN_API __declspec(dllimport)62 #else63 #define PLUGIN_API64 #endif65 #endif66 67 extern68 #ifdef __cplusplus69 "C"70 #endif71 PLUGIN_API PF_ExitFunc PF_initPlugin(const PF_PlatformServices * params);72 73 #ifdef __cplusplus74 }75 #endif76 77 #endif /* PF_PLUGIN_H */
The first thing you need to realize is that this is a C header file. This allows our plug-in framework to be compiled and used by pure C systems, and to write pure C plug-ins. However, this does not limit the use of C. In fact, it has been designed to be more commonly used in C ++.
PF_ProgrammingLanguage
Enumeration allows the plug-in to tell the plug-in manager whether it is implemented by C or C ++.
PF_ObjectParams
Is an abstract structure that is passed in when a plug-in object is created.
PF_PluginAPI_Version
Used to specify the version information. This helps the plug-in Manager to load only compatible versions of plug-ins.
Function pointerPF_CreateFunc
AndPF_DestroyFunc
The plug-in must be used to create and destroy plug-in objects in the plug-in manager.
PF_RegisterParams
The structure contains all the information that the plug-in must provide to the plug-in manager, so that the plug-in manager can initialize the plug-in (version, create, destroy function, and development language ).
PF_RegisterFunc
Function pointers (implemented by the plug-in Manager) allow each plug-inPF_RegisterParams
Structure to register with the plug-in manager. Note: This implementation allows the plug-in to register objects of different versions and to register multiple object types.
PF_InvokeService
A function pointer is a common function that allows a plug-in to call various services provided by the main system, such as logs, event processing, or error reports. This function requires a service name and an opaque pointer pointing to the parameter structure. Plug-ins should know available services and how to call them (or implement a service discovery mechanism ).
PF_PlatformServices
Structure is used to indicate all services provided by the platform (versions, registered objects, and called functions ). This structure is passed to each plug-in during plug-in initialization.
PF_ExitFunc
Is the pointer to the plug-in exit function, implemented by the plug-in.
PF_InitFunc
Is the function pointer of plug-in initialization.
PF_initPlugin
Is the actual Declaration of the function to be initialized by a dynamic plug-in (that is, the plug-in deployed through a dynamically linked library or shared library. It is exposed by the dynamic plug-in, so the plug-in manager can call it when loading the plug-in. It has a pointPF_PlatformServices
Structure pointer, so these services can be called during plug-in initialization (this is the ideal time to register the object), and the function returns the pointer to exit the function.
For static plug-ins (implemented by the static Link Library and directly linked to the main application ),init
Function,NoName itPF_initPlugin
. The reason is that if there are multiple static plug-ins, they cannot have functions with the same name.
The initialization process of static plug-ins is different. They must be explicitly initialized by the main program, that is, throughPF_InitFunc
Call its initialization function. This is actually a poor design, because if you want to add or delete static plug-ins, the main application code must be modified, and those with different namesinit
All functions must be located.
There is a technology called "Automatic Registration" trying to solve this problem. Automatic Registration is implemented by the global object of a static database. This object willmain()
The construction is completed before the function is executed. This global object can request the plug-in Manager to initialize the static plug-in (by passing the plug-ininit()
Function pointer ). Unfortunately, in some versions of Visual C ++, this technology is not supported.
Compile plug-ins
How to compile the plug-in? Our plug-in framework provides the most common functions. It is difficult to add plug-ins that can interact with the main application under current conditions. Therefore, you must build your own application objects based on the plug-in framework again. This means that your applications (loaded plug-ins), together with the plug-in itself, must comply with the same interaction model. This usually means that the application requires the plug-in to provide specific types of objects for exposing certain APIs. The plug-in Framework provides all the required public basic code for plug-in registration, enumeration, and loading.
The following example is defined by the C ++ interface.IActor
. This interface has two operations:getInitialInfo()
Andplay()
. Note that this interface is not sufficient for all situations, becausegetInitialInfo()
The function must pointActorInfo
Structure pointer, andplay()
You need another interface.ITurn
Pointer. This is often the case. You must design this way and specify a specific object model.
1 struct IActor2 {3 virtual ~IActor() {}4 virtual void getInitialInfo(ActorInfo * info) = 0;5 virtual void play( ITurn * turnInfo) = 0;6 };
Each plug-in can be registeredIActor
Multiple implementations of the interface. When the application decides to instantiate an object registered by the plug-in, it callsPF_CreateFunc
Function. The plug-in will respond, create an object and return it to the application. Function return value isvoid *
Because the object creation operation is part of the general plug-in framework, you do not know any specificIActor
Interface Information. The application is responsiblevoid *
ConvertIActor *
And then call its functions through interfaces like other objects. When the application is used upIActor
The registeredPF_DestroyFunc
Function, the plug-in will destroy this object. As to why virtual destructor are required, we will discuss it later.
Turn: Write the plug-in framework by yourself (2)