diff options
Diffstat (limited to 'src/plugger.h')
-rw-r--r-- | src/plugger.h | 107 |
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 | |||
20 | namespace Bu | 25 | namespace 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 |