first, the introduction of plug-in architecture
Think of writing a blog, also did not think of a better name, at present, first life this name it. When it comes to plug-in architecture, perhaps most it practitioners have heard or some of the bulls themselves have implemented a stable and efficient plug-in framework. There are a lot of software and libraries are based on plug-in architectures, such as PS, GIS software in my industry such as ArcGIS, QGIS, as well as open source graphics engine ogre and OSG, these are plug-in architectures, through the plug-in architecture to expand the functionality. What is the plug-in architecture anyway? My understanding is that when the system is running in need of a function of the dynamic loading module, Plug-ins are usually implemented by dynamic link library, of course, can also use static libraries, such as some embedded systems, such as iOS is said to not support the dynamic link library.
Why should we use plug-in architecture?
Modern software engineering has evolved from the original general-purpose library to the application framework, for example, some C + + library, these libraries are to achieve a certain domain-specific functions, such as gdal, to achieve a variety of spatial data format analysis, such libraries are not usually based on plug-in architecture; application framework such as Java inside the three major frameworks. First of all, suppose a scenario, in the case of C + + development application, our architecture is based on the traditional architecture of app+dll, all the functions are leelawadee together, so that as the system grows larger, the various modules are coupled together, and when one of the modules is modified, the other modules are affected along with it. If these two modular different developers are responsible for, it is necessary to communicate well in advance, which caused the difficulty of modifying maintenance. How to solve this problem, the plug-in architecture is an option. So what are the benefits of the plugin architecture?
1, the convenience function expansion . For example, in the design of GIS engines, the general practice is not to put the data format parsing in the GIS kernel, only in the kernel to define some common data load resolution interface, and then through plug-ins to achieve a specific format of the resolution, so you can extend a variety of different data formats, but also easy to transplant.
2, the update quantity is small . When the underlying interface is unchanged, the functionality that exists as a plug-in can easily be updated independently of the application, with the introduction of a new version of the plugin. This is a much smaller amount of update than publishing the entire application.
3, Reduce the dependencies between modules, can support parallel development . For example, two developers develop different functions of plug-ins, they can only care about the implementation of their plug-in functions, can achieve rapid development.
4, facing the future . When your API reaches a certain level of stability, your API may not be updated as necessary. However, the functionality of the API can be further evolved through plug-ins, making it possible for the API to remain available and adaptable for an extended period of time so that your APIs are not discarded.
second, the plug-in needs to design things
Here I only consider the situation of the dynamic link library. We need a mechanism to load the dynamic link library and access the symbols. In a generic plug-in system, the plug-in API and the plugin manager must be designed.
Plug-in API. This is the creation of Plug-ins must provide the interface, C + + implementation is an abstract class, which only provides interface, specific functions to the plug-in implementation. This part of the code should be within your core API.
plug-in manager . The plug-in manager is responsible for loading, registering, and uninstalling functions of plug-ins, managing the entire lifecycle of Plug-ins. This class is generally designed as a single case pattern, in fact most of the resource management classes are generally designed as a single case pattern.
The relationship between the plug-in and the core API is as follows.
When we load the plugin in, at this time still do not know how to run plug-ins, in order to let the plug-in normal operation, this time need to know the core API should access which specific function to achieve the normal operation of Plug-ins, the definition of the entry function, this can be exported standard C interface mode to implement plug-in initialization, stop and so on.
The following are examples of specific definitions of export symbols and standard C interfaces.
#ifdef plugincore_exports
#ifdef __gnuc__
#define PLUGINCORE_API __attribute__ ((dllexport))
#else
#define PLUGINCORE_API __declspec (dllexport)
#endif
#else
#ifdef __gnuc__
#define PLUGINCORE_API __ ATTRIBUTE__ ((dllimport))
#else
#define PLUGINCORE_API __declspec (dllimport)
#endif
#endif
extern "C" Plugincore_api plugininstance *startplugin ();
extern "C" Plugincore_api void Stopplugin ();
The above startplugin is the dynamic library load when the need to access the symbol, this function inside to start the plug-in, Stopplugin is the uninstall plug-in needs to call the function.
Here use the dynamic library to import, on the dynamic library on different platforms have different extensions and load functions, in order to maintain the cross-platform nature of the API, I here simply encapsulate the dynamic library loading and unloading process, with a typedef void* HLIB; Represents a handle to a dynamic library. The following class is also presented to the reader, and the suggestions are inappropriate.
#ifndef dynamiclib_include #define DYNAMICLIB_INCLUDE//dynamic library load, take function address for internal use #include "Export.h" class Dynamiclib {public:
Dynamiclib (void);
~dynamiclib (void);
Const char* GetName () const;
Load Dynamic library bool Loadlib (const char* strlibname);
void* getsymboladdress (const char* strsymbolname) const;
void Freelib (); Private:hlib M_hdynlib; Dynamic library handle char* m_pszlibname;
dynamic Library name};
#endif #include "DynamicLib.h" Dynamiclib::D ynamiclib (void) {m_hdynlib = NULL;
M_pszlibname = NULL;
} dynamiclib::~dynamiclib (void) {if (m_hdynlib!= NULL) {freelib ();
} if (M_pszlibname!= NULL) {free (m_pszlibname);
M_pszlibname = NULL;
} const char* Dynamiclib::getname () const {return m_pszlibname;} #if defined (__unix__) | | Defined (Unix) #include <dlfcn.h> bool Dynamiclib::loadlib (const char* strlibname) {std::string strName = Strlibna
Me
StrName + = ". So";
M_hdynlib = Dlopen (Strname.c_str (), rtld_lazy);
if (plibrary = = NULL) {return 0; } m_pszlibname = strDUP (Strlibname);
return (1);
} void* dynamiclib::getsymboladdress (const char* strsymbolname) const {void *psymbol = NULL;
if (m_hdynlib!= NULL) {Psymbol = Dlsym (m_hdynlib,strsymbolname);
return psymbol;
} void Dynamiclib::freelib () {if (m_hdynlib!= NULL) {dlclose (m_hdynlib);
M_hdynlib = NULL;
} if (M_pszlibname!= NULL) {free (m_pszlibname);
M_pszlibname = NULL; } #endif #ifdef _win32 #include <Windows.h> bool Dynamiclib::loadlib (const char* strlibname) {std::string str
Name = Strlibname;
StrName + = ". dll";
M_hdynlib = LoadLibrary (Strname.c_str ());
if (m_hdynlib!= NULL) {m_pszlibname = StrDup (strlibname);
return 1;
return 0; } void* dynamiclib::getsymboladdress (const char* strsymbolname) Const {if (M_hdynlib!= NULL) {return (void*) Getpro
CAddress ((hmodule) m_hdynlib,strsymbolname);
return NULL;
} void Dynamiclib::freelib () {if (m_hdynlib!= NULL) {freelibrary (hmodule) m_hdynlib);
M_hdynlib = NULL;
}if (m_pszlibname!= NULL) {free (m_pszlibname);
M_pszlibname = NULL;
}} #endif
Almost forgot, the plug-in system must be designed plug-in API and plugin manager have not said, in fact, plug-in manager is a collection of plug-in instances, the plug-in Manager provides loading and unloading a plug-in function, the following is the plug-in API and plug-in manager instance.
#ifndef plugininstance_include #define Plugininstance_include #include "Export.h" class Plugincore_api Plugininstance {
Public:explicit plugininstance (const std::string &strname);
Virtual ~plugininstance (void);
virtual bool Load () = 0;
virtual bool UnLoad () = 0;
Return plug-in name, with suffix, such as DLL virtual std::string getfilename () const = 0;
Returns the name of the plug-in, without the suffix virtual std::string getdisplayname () const = 0;
Private:plugininstance (const plugininstance &RHS);
Const plugininstance &operator= (const plugininstance &RHS);
};
The function called when the plug-in loads and unloads the typedef plugininstance * (*start_plugin_fun) ();
typedef void (*stop_plugin_fun) ();
#endif #ifndef pluginmanager_include #define Pluginmanager_include #include "Export.h" class plugininstance;
Class Dynamiclib;
Class Plugincore_api PlugInManager {public:static pluginmanager &getinstance ();
BOOL Loadall ();
plugininstance* Load (const std::string &strname,int &errcode);
BOOL Loadplugin (plugininstance *pplugin); BOOL Unloadall ();
BOOL UnLoad (const std::string &strname);
BOOL Unloadplugin (plugininstance *pplugin);
Std::vector<plugininstance *> getallplugins ();
Private:pluginmanager (void);
~pluginmanager (void);
PlugInManager (const PlugInManager &RHS);
Const PlugInManager &operator= (const PlugInManager &RHS); Std::vector<plugininstance *> M_vecplugins; Plug-in instance handle std::map<std::string,dynamiclib *> m_vecpluginlibs;
Plug-in module handle};
#endif
The plug-in manager can be preconfigured with the configuration files of the system to add to which plug-ins, typically available in an XML configuration.
With the above introduction, it is time to begin to introduce the entire plug-in loading and unloading process, first to introduce how to load. Loaded function-type plugininstance* load (const std::string &strname,int &errcode);
The function is to pass in a plug-in dynamic library name without a suffix, if the plugin manager does not have the plug-in loaded into the system, and registered in the list of plug-ins, if there is a plug-in list to access the name of Plug-ins, return the plug-in instance. The implementation of this function is as follows:
plugininstance* pluginmanager::load (const std::string &strname,int &errcode)
{
STD::MAP<STD:: String,dynamiclib *>::iterator iter = M_vecpluginlibs.find (strName);
if (iter = = M_vecpluginlibs.end ()) //does not exist you need to insert
{
dynamiclib* pLib = new Dynamiclib;
if (PLib!= NULL)
{
plib->loadlib (strname.c_str ());
M_vecpluginlibs.insert (Make_pair (Strname,plib));
Start_plugin_fun Pfun = (start_plugin_fun) plib->getsymboladdress ("Startplugin");
if (Pfun!= NULL)
{
plugininstance* pplugin = Pfun ();
Errcode = 1;
return pplugin;
}
Errcode = 0;
return NULL;
}
}
else if (ITER!= m_vecpluginlibs.end ()) //If present, look for plugins in the plugin list where the name is strname
{for
(int i = 0; i < M_vecplugin S.size (); i + +)
{
if (StrName = = M_vecplugins[i]->getdisplayname ())
{
errcode = 1;
return m_vecplugins[i];
}} Errcode = 0;
return NULL;
}
From the above process can be seen, first detect whether the plug-in exists, if it exists, in the list of Plug-ins to find the plug-in directly return the plug-in instance. If it does not exist, you need to first create a dynamiclib* PLib = new Dynamiclib, and then import the plug-in dynamic library file named strname by PLib, and then add the module handle and name to the module list. Then through the function of dynamiclib getsymboladdress to get function pointer, functions named Startplugin, and finally through the function pointer callback to return the plug-in instance and the plugin to register the plug-in list, the function of the specific implementation of the plug-in is as follows:
static Plugininstance *pplugin = NULL;
plugininstance* Startplugin ()
{
pplugin = new Shapeplugin ("Shapefile");
Pluginmanager::getinstance (). Loadplugin (pplugin);
return pplugin;
}
BOOL Pluginmanager::unload (const std::string &strname)
{
std::map<std::string,dynamiclib *>:: Iterator iter = M_vecpluginlibs.begin ();
for (; Iter!= m_vecpluginlibs.end (); ++iter)
{
Dynamiclib *plib = iter->second;
if (NULL = = PLib)
{
continue
}
if (strcmp (Plib->getname (), strname.c_str ()) = = 0)
{
Stop_plugin_fun pfun = (stop_plugin_fun) plib-> Getsymboladdress ("Stopplugin");
if (Pfun!= NULL)
{
pfun ();
}
Plib->freelib ();
Delete PLib;
Then remove m_vecpluginlibs.erase from the list
(ITER);
return true;
}
return false;
}
Shapeplugin is a plug-in that inherits from Plugininstance.
The process of uninstalling the plug-in is exactly the opposite, and the implementation code is given below.
BOOL Pluginmanager::unload (const std::string &strname)
{
std::map<std::string,dynamiclib *>:: Iterator iter = M_vecpluginlibs.begin ();
for (; Iter!= m_vecpluginlibs.end (); ++iter)
{
Dynamiclib *plib = iter->second;
if (NULL = = PLib)
{
continue
}
if (strcmp (Plib->getname (), strname.c_str ()) = = 0)
{
Stop_plugin_fun pfun = (stop_plugin_fun) plib-> Getsymboladdress ("Stopplugin");
if (Pfun!= NULL)
{
pfun ();
}
Plib->freelib ();
Delete PLib;
Then remove m_vecpluginlibs.erase from the list
(ITER);
return true;
}
return false;
}
So the whole process of the plugin went through, Long March first step, now just implement the plug-in registration and call, the following one is going to realize how to implement the specific plug-ins and how to implement the communication between the plug-ins.
Third, PostScriptThis article is mainly in the exploration of C + + plug-in implementation mechanism of some personal understanding, although the function is still very few, but some basic things still have. The code for this plug-in instance is downloaded at: http://download.csdn.net/detail/zhouxuguang236/7466253 Note After downloading please read the instructions first.