diff options
| author | Mike Buland <eichlan@xagasoft.com> | 2011-01-12 18:58:30 +0000 |
|---|---|---|
| committer | Mike Buland <eichlan@xagasoft.com> | 2011-01-12 18:58:30 +0000 |
| commit | 4e0cd382dc4252306e0c2dc880c06b1fa4857c89 (patch) | |
| tree | ad98a7156d5109d233619444c10a4c8015dfcf40 /src | |
| parent | 2ba3f84ab559da02a11aa000b3cecb3b3668af61 (diff) | |
| download | libbu++-4e0cd382dc4252306e0c2dc880c06b1fa4857c89.tar.gz libbu++-4e0cd382dc4252306e0c2dc880c06b1fa4857c89.tar.bz2 libbu++-4e0cd382dc4252306e0c2dc880c06b1fa4857c89.tar.xz libbu++-4e0cd382dc4252306e0c2dc880c06b1fa4857c89.zip | |
Plugger works on windows!
Diffstat (limited to 'src')
| -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 |
