summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/plugger.cpp4
-rw-r--r--src/plugger.h101
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
12namespace Bu { subExceptionDef( PluginException ) } 10namespace 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
20namespace Bu 23namespace 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