aboutsummaryrefslogtreecommitdiff
path: root/src/plugger.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugger.h')
-rw-r--r--src/plugger.h107
1 files changed, 89 insertions, 18 deletions
diff --git a/src/plugger.h b/src/plugger.h
index 65ac4bb..2ba7b4b 100644
--- a/src/plugger.h
+++ b/src/plugger.h
@@ -8,15 +8,20 @@
8#ifndef BU_PLUGGER_H 8#ifndef BU_PLUGGER_H
9#define BU_PLUGGER_H 9#define BU_PLUGGER_H
10 10
11#ifndef WIN32 //yeah, this one is going to take some work...
12
13#include "bu/hash.h" 11#include "bu/hash.h"
14#include "bu/list.h" 12#include "bu/list.h"
15#include <dlfcn.h>
16#include "bu/exceptionbase.h" 13#include "bu/exceptionbase.h"
17#include "bu/string.h" 14#include "bu/string.h"
18#include <stddef.h> 15#include <stddef.h>
19 16
17#include "bu/config.h"
18
19#ifdef WIN32
20# include <windows.h>
21#else
22# include <dlfcn.h>
23#endif
24
20namespace Bu 25namespace Bu
21{ 26{
22 subExceptionDecl( PluginException ); 27 subExceptionDecl( PluginException );
@@ -34,7 +39,11 @@ namespace Bu
34 typedef struct PluginReg 39 typedef struct PluginReg
35 { 40 {
36 bool bBuiltin; 41 bool bBuiltin;
42#ifdef WIN32
43 HMODULE dlHandle;
44#else
37 void *dlHandle; 45 void *dlHandle;
46#endif
38 PluginInfo *pInfo; 47 PluginInfo *pInfo;
39 } PluginReg; 48 } PluginReg;
40 49
@@ -69,6 +78,20 @@ namespace Bu
69 (void (*)( void * ))(destroy ##classname) }; \ 78 (void (*)( void * ))(destroy ##classname) }; \
70 } 79 }
71 80
81//
82// This is probably the main interface to use, I'll describe it some here...
83// structname - The name of the structure, this is what you have to pass to
84// register. Depending on how you build your dll/so files this
85// will need to be unique (generally not)
86// pluginname - This is what will be used by the plugin system to refer to
87// your plugin once it's loaded. This should be unique, but not
88// a string
89// classname - The name of the class that is the plugin
90// baseclass - The name of the base class that is the parent of the plugin
91// name - The name of the author of this class (or company)
92// ver - an integer version number for the plugin
93// rev - an integer revision number for the plugin
94//
72#define PluginInterface3( structname, pluginname, classname, baseclass, name, ver, rev ) \ 95#define PluginInterface3( structname, pluginname, classname, baseclass, name, ver, rev ) \
73 extern "C" { \ 96 extern "C" { \
74 baseclass *create ##classname() \ 97 baseclass *create ##classname() \
@@ -85,6 +108,38 @@ namespace Bu
85 (void (*)( void * ))(destroy ##classname) }; \ 108 (void (*)( void * ))(destroy ##classname) }; \
86 } 109 }
87 110
111 /**
112 * A complete dynamic plugin manager system. This will allow you to design
113 * and use plugins that are compiled into your program and dynamically
114 * linked to your program interchangably. It works on windows and on *nix
115 * and bsd type systems (anything that supports dlopen). Basically you
116 * create a base class that will be the basic interface of your plugins.
117 * Then you create some classes that inherit from it, and use the
118 * PluginInterface3 macro to create the required data structures for it.
119 *
120 * Once you have plugins you can create a Plugger, by passing in the base
121 * class as it's template parameter. Once it's created, you can register
122 * plugins. To register a plugin that is builtin, you just need to pass
123 * a pointer to it's interface structure to the registerBuiltinPlugin
124 * function. To register a plugin that is in a shared object or dll file
125 * you just pass the filename (with path, probably), and the name of the
126 * structure to load and you're all set.
127 *
128 * To instantiate an object from a plugin simply call instantiate with the
129 * name of the plugin as specified in the interface macro. To destroy an
130 * object crated with the plugger do not delete it, instead pass it into
131 * Plugger's destroy function.
132 *
133 * Any objects not destroyed when the plugger is deleted will be destroyed
134 * automatically.
135 *
136 * It is important to note that some systems (linux at least) partition off
137 * the memory allocated by objects linked in at run time into a seperate
138 * segment that, while it can be accessed by the main program, cannot be
139 * safely or reliably freed by the main program. With that in mind it is
140 * a good idea to free all memory allocated by a plugin object in the plugin
141 * object and not allow the calling program to delete it.
142 */
88 template<class T> 143 template<class T>
89 class Plugger 144 class Plugger
90 { 145 {
@@ -111,7 +166,11 @@ namespace Bu
111 { 166 {
112 if( (*i)->bBuiltin == false ) 167 if( (*i)->bBuiltin == false )
113 { 168 {
169#ifdef WIN32
170 FreeLibrary( (*i)->dlHandle );
171#else
114 dlclose( (*i)->dlHandle ); 172 dlclose( (*i)->dlHandle );
173#endif
115 } 174 }
116 delete (*i); 175 delete (*i);
117 } 176 }
@@ -129,32 +188,42 @@ namespace Bu
129 const Bu::String &sPluginName ) 188 const Bu::String &sPluginName )
130 { 189 {
131 PluginReg *pReg; 190 PluginReg *pReg;
132 try { 191 if( hPlugin.has( sPluginName ) )
133 pReg = (PluginReg *)hPlugin[sPluginName]; 192 throw Bu::ExceptionBase("A plugin with name '%s' is already "
134 hPlugin.erase( sPluginName ); 193 "loaded.", sPluginName.getStr() );
135 dlclose( pReg->dlHandle );
136 delete pReg;
137 pReg = NULL;
138 } catch( Bu::HashException &e )
139 {
140 }
141 194
142 pReg = new PluginReg; 195 pReg = new PluginReg;
143 196
144 pReg->bBuiltin = false; 197 pReg->bBuiltin = false;
198#ifdef WIN32
199 pReg->dlHandle = LoadLibrary( sFName.getStr() );
200 if( pReg->dlHandle == NULL )
201 {
202 throw PluginException( 1, "Error opening %s: %s",
203 sFName.getStr(), Bu::getLastWinError().getStr() );
204 }
205 pReg->pInfo = (PluginInfo *)GetProcAddress( pReg->dlHandle,
206 sPluginName.getStr() );
207 if( pReg->pInfo == NULL )
208 {
209 throw PluginException( 2, "Error mapping %s: %s",
210 sFName.getStr(), Bu::getLastWinError().getStr() );
211 }
212#else
145 pReg->dlHandle = dlopen( sFName.getStr(), RTLD_NOW ); 213 pReg->dlHandle = dlopen( sFName.getStr(), RTLD_NOW );
146 if( pReg->dlHandle == NULL ) 214 if( pReg->dlHandle == NULL )
147 { 215 {
148 throw PluginException( 1, "Error on %s: %s", sFName.getStr(), 216 throw PluginException( 1, "Error opening %s: %s",
149 dlerror() ); 217 sFName.getStr(), dlerror() );
150 } 218 }
151 pReg->pInfo = (PluginInfo *)dlsym( pReg->dlHandle, 219 pReg->pInfo = (PluginInfo *)dlsym( pReg->dlHandle,
152 sPluginName.getStr() ); 220 sPluginName.getStr() );
153 if( pReg->pInfo == NULL ) 221 if( pReg->pInfo == NULL )
154 { 222 {
155 throw PluginException( 2, "Error on %s: %s", sFName.getStr(), 223 throw PluginException( 2, "Error mapping %s: %s",
156 dlerror() ); 224 sFName.getStr(), dlerror() );
157 } 225 }
226#endif
158 hPlugin.insert( pReg->pInfo->sID, pReg ); 227 hPlugin.insert( pReg->pInfo->sID, pReg );
159 } 228 }
160 229
@@ -195,7 +264,11 @@ namespace Bu
195 { 264 {
196 if( (*i)->bBuiltin == false ) 265 if( (*i)->bBuiltin == false )
197 { 266 {
267#ifdef WIN32
268 FreeLibrary( (*i)->dlHandle );
269#else
198 dlclose( (*i)->dlHandle ); 270 dlclose( (*i)->dlHandle );
271#endif
199 } 272 }
200 delete (*i); 273 delete (*i);
201 } 274 }
@@ -213,6 +286,4 @@ namespace Bu
213 }; 286 };
214} 287}
215 288
216#endif //#ifndef WIN32 //yeah, this one is going to take some work...
217
218#endif 289#endif