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