   Plugin Architecture
  Hello everybody. I am currently developing a level editor, and I want to use a plugin architecture so it can be more flexible. I want the plugins to access the application, to interact with it (I think that's pretty usual). The problem is that I get linker errors when I try to use the application classes inside the plugin, I'm not sure but I think those errors seems to be natural, as the application code need to be exported to the dll somehow.The architecture I used is similar to the one described in this article.And is also similar to a chapter on the book "C++ for game developers": I export to the dll a 'factory' function, that the dll implement to instantiate the plugin class.The drawback that I see on those references is that the plugin examples are very simple, just a "print something" thing, so they do not explain how to access application code from the plugin.I already coded an architecture similar to those, I can load the plugin dll, and got them running, as long as they don't access any code that is in the application (with the exception of a IPlugin interface, which the plugin class implements - I dont know why this works [looksaround]).I have already read this thread.The code I implemented is something similar to what pjcast said:"...when you load the dll (which has classes which implement these interfaces) you import a simple C function from the DLL, call that function, which will create the C++ class, and than register it to the main application."Which is how the Ogre plugin architecture is implemented, and is also something similar to what is described on the article of the first link I mentioned.I found this article, about exporting C++ classes to dlls.I think that this could be a solution, but I really dont like solutions like that, that use tricks with the language and makes the code less clean.So, do anyone know a better way to solve that problem? Maybe I should export only functions and make the plugin access to the application more restrict (or not, if I have the patience to export zillions of functions hehehe); or break the application in libs so that the code can be linked with the dll (looks like in 3d studio max is used something like this), but I would have to rewrite a lot of code hehe.I am not still sure if this is a linker issue or if there is something wrong with the plugin mechanism.Thanks in advance, sorry for the long text, and my 'weird' english hehehe.Cheers[Edited by - rafa_gdev on May 9, 2009 7:19:01 PM]
  Well, if you're getting linker errors, why don't you just post the compiler output?   ;  oh sure! I'll also put some code here:This is the plugin interface, very simple at the moment (its on the application code):class IPlugin{public:virtual ~IPlugin() {};virtual const std::string getName() = 0;virtual void about() = 0;protected:std::string mName;};// DLL export declaration#ifdef PLUG_EXPORTS#define _PluginDecl __declspec(dllexport)#else#define _PluginDecl __declspec(dllimport)#endifextern "C" _PluginDecl Ballisto::IPlugin* CreatePlugin();typedef Ballisto::IPlugin* (*CREATEPLUGIN)();DLLs are loaded in the well known windows way: LoadLibrary(), GetProcAddress(), FreeLibrary().This is a very simple DLL to test the idea:#include "BallistoStableHeaders.h"#include "TestPlugin.h"using namespace Ballisto;extern "C" _PluginDecl IPlugin* CreatePlugin(){return new TestPlugin();}And this is the test plugin itself (plugin code, of course):class TestPlugin: public IPlugin{public:TestPlugin(){MessageBoxA( NULL, "Plugin Loaded", "Test", 0);}virtual const std::string getName(){return "TestPlugin";}virtual void about(){}};This code works fine, because the plugin doesn't access any application code. However, if I try to do so inside the plugin, like this:PluginManager& pluginManager = PluginManager::getSingleton();Or even a simple #include "PluginManager.h", I get a linker error, saying that the symbol could not be found:TestPluginDLL.obj : error LNK2001: unresolved external symbol "protected: static class Ballisto::PluginManager * Ogre::Singleton<class Ballisto::PluginManager>::ms_Singleton" (?ms_Singleton@?$Singleton@VPluginManager@Ballisto@@@Ogre@@1PAVPluginManager@Ballisto@@A)Thanks.;  Well simply link the plugin with the application: a .exe and a .dll are almost the same, you can export elements from a .exe just like you would export them from a dll.An alternative - which is usually favored - is to have the application elements as interfaces as well, and the application implementing them. Technically your interface is more an abstract class than a reference since you have that virtual destructor. Also you might want to make that get_name const and return by reference or get passed a string reference.   ;Quote:Original post by rafa_gdevoh sure! I'll also put some code here:Don't ever ever use STL in a plugin interface! If you release a (release) build of your app, when compiling a debug plug-in the size of std::vector/std::string will be different, and will crash when passing an instance of an STL container across the DLL bounds. Other problems include people using STLport vs MS etc.I'd change the plugin interface too:class IPlugin{public:  virtual ~IPlugin() {};  virtual const char* getName() = 0;  virtual const char* author() = 0;  virtual const char* version() = 0;  virtual const char* description() = 0;  // dont use any member variables!};// general app interfaceclass EXPORT App{public:  // provides pointer to plugin manager etc  PluginManager* getPluginManager();};typedef extern "C" Ballisto::IPlugin* (*CreatePluginFunc)(App* pApp);and the plugin implementation to something like this:class MyPlugin : public IPlugin{public:  virtual const char* getName() { return "Test" }  virtual const char* author() { return "Test Person" }  virtual const char* version() { return "1.0" }  virtual const char* description() { return "just a quick test" }};// global pointer in pluginApp* gApplication=0;extern "C" EXPORT Ballisto::IPlugin* CreatePlugin(App* pApp){  // store app interface  gApplication = pApp;  // return instance  return new MyPlugin();}That way you don't need to worry about exporting static variables and all that crap since you have full access to the application. If you don't want to link to the app.exe at all, then turn App into an interface and hide the derived version that provides the implementation.[Edited by - RobTheBloke on May 11, 2009 4:02:47 AM];Quote:Don't ever ever use STL in a plugin interface! Oh, I didnt know that, thanks.So, looks like the best thing I should do is to have a 2nd dll that will contain the interface of the application elements? Something like:- IApplication.dll (IPluginManager, IControllerManager, ISkybox, IMesh...)- Application.exe (The application itself, that implements those interfaces)- PluginX.dll (which also uses IApplication.dll, in this case to gain access to the application)Thank you all for the replies, things are getting much more clear now :)I really was in a "dead end" hehe.   ;Quote:Original post by RobTheBlokeDon't ever ever use STL in a plugin interface! If you release a (release) build of your app, when compiling a debug plug-in the size of std::vector/std::string will be different, and will crash when passing an instance of an STL container across the DLL bounds. Other problems include people using STLport vs MS etc.Let's revert back to C :)This really depends who is writing plugins for the level editor. If it's just him/his team then just use the std template classes. Don't just quit using the standard library because of this. You could for example write a wrapper to get around that problem:class LIBRARY_EXPORT_API string{    class private_string;    private_string *d;public:    string();    string( const char * );    // Define all the functions that std::string offers.    // Well, the ones that you think you will need.};// Hidden in the cpp fileclass string::private_string{public:    std::string data;};// Now implement all those functions from above by calling the// function from the std::string instead.// Of course you will need to be careful when copy-constructing,// assigning, so you will need some sort of shared_ptr.This is a similar way as to Qt handles such things. However only go that way if you feel up to it. Otherwise (especially when you're the only one ever writing a plugin) just use the STL anyway.   