SFML community forums

General => Feature requests => Topic started by: Core Xii on October 13, 2008, 06:48:03 am

Title: DLL convenience wrapper
Post by: Core Xii on October 13, 2008, 06:48:03 am
I'd like a cross-platform convenience interface for explicitly linking DLLs at run-time. I'd like to implement plugin architectures in my applications but am faced with an overwhelming complexity and complete lack of information for actually achieving this. Easy-to-use functions for loading DLLs at specified file paths, and calling functions from them.
Title: DLL convenience wrapper
Post by: Laurent on October 13, 2008, 08:22:36 am
It's very easy, if you want an example just have a look at the Ogre engine source code, there's a very simple class (with macros for each OS) which does this job.

Basically, the functions to call are :
- LoadLibrary, GetProcAddress, FreeLibrary on Windows
- dlopen, dlsym, dlclose on Linux (not 100% sure of the names)
- no idea on MacOs
Title: DLL convenience wrapper
Post by: Core Xii on October 13, 2008, 07:14:42 pm
I'm sure it's easy, but I wouldn't care writing countless compiler conditions for the different operating systems. I'd appreciate it if you did it, but I'll take a look at Ogre, thanks.
Title: DLL convenience wrapper
Post by: Laurent on October 13, 2008, 10:34:18 pm
So you're lazy and want me to write your class ? Or is it an interesting feature that you'd love to see in SFML for all users ? ;)
Title: DLL convenience wrapper
Post by: Core Xii on October 13, 2008, 10:56:03 pm
:P Not lazy, just inexperienced. I only recently discovered SFML and it looks more favorable over SDL. This would be the icing on the cake. I don't need it right now and I don't know how useful other people find it, but it would indeed be a useful thing to have in the future.

After all, the convenience of easy-of-use and cross-platform compatibility out-of-the-box is exactly why I would (will?) use this library.
Title: DLL convenience wrapper
Post by: bullno1 on October 14, 2008, 05:45:11 am
It's already cross-platform and it already has a C wrapper.

Quote
After all, the convenience of easy-of-use and cross-platform compatibility out-of-the-box is exactly why I would (will?) use this library.

Sorry but I think most of the people find that linking to a dynamic library during compile time(let the compiler generate the loader) is easier than using platform-dependent code to load it during runtime.
Title: DLL convenience wrapper
Post by: Core Xii on October 14, 2008, 06:30:38 am
Quote from: "bullno1"
It's already cross-platform and it already has a C wrapper.
I'm sorry, what are you talking about?

Quote from: "bullno1"
Sorry but I think most of the people find that linking to a dynamic library during compile time(let the compiler generate the loader) is easier than using platform-dependent code to load it during runtime.
Easy is good. But the problem here is that compile-time linking does not allow you to provide a plugin system.
Title: DLL convenience wrapper
Post by: Wizzard on October 14, 2008, 08:26:54 am
You will find oftentimes that using a scripting language is better than creating a plug-in system via DLLs.
In such cases where you would think that you would need to interface with DLLs, you can usually load DLLs with the scripting language.
For an example of a scripting language that has DLL support, check out Lua (http://www.lua.org/home.html) and it's require function.
Title: DLL convenience wrapper
Post by: Laurent on October 14, 2008, 08:28:25 am
Quote
It's already cross-platform and it already has a C wrapper.

He doesn't want to dynamically link SFML, he wants to have a class in SFML which can load dynamic libraries at runtime to build plugin systems.

Quote
I don't need it right now and I don't know how useful other people find it, but it would indeed be a useful thing to have in the future.

Actually, I'm still hesitating to add this kind of class. For sure it would be useful, but so are so many classes, and I don't want SFML to become a big / bloated general cross-platform framework. I'd like to stay focused on multimedia.
Title: DLL convenience wrapper
Post by: SirJulio on October 14, 2008, 09:00:26 am
Quote from: "Wizzard"
You will find oftentimes that using a scripting language is better than creating a plug-in system via DLLs.


I agree.

If you can design a dll-like plugin system, you can write your own multi-platform loader (the 3 fonctions that Laurent gave above (AFAIK Mac and linux use the same)).

A scripting module would be a very interresting thing, but i don't even know how this can be done (genericity, portability, integration with current modules ....). This is indeed a huge work, but scripting languages (python, lua, or others) are easy to use, it would be a nice feat for SFML. =)
Title: DLL convenience wrapper
Post by: Core Xii on October 14, 2008, 09:50:04 pm
Quote from: "Laurent"
Actually, I'm still hesitating to add this kind of class. For sure it would be useful, but so are so many classes, and I don't want SFML to become a big / bloated general cross-platform framework. I'd like to stay focused on multimedia.

Well you don't have to include it by default, make it optional.

I don't like the idea of having to use scripting, it's slow, and one would have to learn said language. It would also mean the source for the plugins would be exposed, not necessarily an acceptable condition in all situations.

I took a look at Ogre but the functionality is too entangled with the rest of the library for me to separate. I certainly don't want to link to Ogre for that alone.
Title: DLL convenience wrapper
Post by: Wizzard on October 15, 2008, 12:30:09 am
Quote from: "Core Xii"
I don't need it right now and I don't know how useful other people find it, but it would indeed be a useful thing to have in the future..


So, you do need it? You should tell us the plans you have with this, because right now it doesn't seem too likely that were going to do it for you.
Title: DLL convenience wrapper
Post by: Core Xii on October 15, 2008, 03:35:58 am
I have two applications for it that I can immediately think of. A plugin system for an editor defining data and exports (I'm making a vector-based graphics program that'll also be used as a level editor for several games), and full modability for a big project via callbacks.

If I actually had it so easy and at my disposal, I'm sure I'd find good use for it.
Title: DLL convenience wrapper
Post by: Laurent on October 15, 2008, 09:41:22 am
Quote
I took a look at Ogre but the functionality is too entangled with the rest of the library for me to separate

No, there's a tiny DynLib class which just does this job. You just have to ignore the log and error handling.

http://ogre.svn.sourceforge.net/viewvc/ogre/trunk/OgreMain/include/OgreDynLib.h?view=markup
http://ogre.svn.sourceforge.net/viewvc/ogre/trunk/OgreMain/src/OgreDynLib.cpp?view=markup
Title: DLL convenience wrapper
Post by: Core Xii on October 15, 2008, 01:00:54 pm
Right but I'd need to link to Ogre. Bit of a big an engine to link to for one class.
Title: DLL convenience wrapper
Post by: Laurent on October 15, 2008, 01:43:16 pm
Write your own class (or extract and adapt Ogre's one) ; all you need to know is the name of the 3 functions to call for each OS, and this can be found in Ogre's class.
Title: DLL convenience wrapper
Post by: Core Xii on October 15, 2008, 02:21:03 pm
And, like I said, Ogre's is too entangled to the rest of the engine for me to extract.
Title: DLL convenience wrapper
Post by: Laurent on October 15, 2008, 02:40:55 pm
What are you talking about ? The class is almost empty, except the 3 OS-specific calls you have to make. The rest is logging and error handling, which is straight-forward to remove.
Title: DLL convenience wrapper
Post by: zarka on October 15, 2008, 09:58:01 pm
Quote from: "Core Xii"
Right but I'd need to link to Ogre. Bit of a big an engine to link to for one class.


umm as laurent has pointed out a lot of times.. this class is dead simple to rip out.. i did it in ~15min including a test run.

here it is btw.. one thing to remember though is that since this is slightly modified OGRE code it will fall into the LGPL license.

header file
Code: [Select]

#ifndef _DynLib_H__
#define _DynLib_H__

#include <string>
#include "sfml/System.hpp"

#if defined(SFML_SYSTEM_WINDOWS)
#    define DYNLIB_HANDLE hInstance
#    define DYNLIB_LOAD( a ) LoadLibraryExA( a, NULL, LOAD_WITH_ALTERED_SEARCH_PATH )
#    define DYNLIB_GETSYM( a, b ) GetProcAddress( a, b )
#    define DYNLIB_UNLOAD( a ) !FreeLibrary( a )

struct HINSTANCE__;
typedef struct HINSTANCE__* hInstance;

#elif defined(SFML_SYSTEM_LINUX)
#    define DYNLIB_HANDLE void*
#    define DYNLIB_LOAD( a ) dlopen( a, RTLD_LAZY | RTLD_GLOBAL)
#    define DYNLIB_GETSYM( a, b ) dlsym( a, b )
#    define DYNLIB_UNLOAD( a ) dlclose( a )

#elif defined(SFML_SYSTEM_MACOS)
#    define DYNLIB_HANDLE CFBundleRef
#    define DYNLIB_LOAD( a ) mac_loadExeBundle( a )
#    define DYNLIB_GETSYM( a, b ) mac_getBundleSym( a, b )
#    define DYNLIB_UNLOAD( a ) mac_unloadExeBundle( a )
#endif

namespace sf
{
class DynLib
    {
protected:
std::string mName;
std::string dynlibError(void);
    public:
        DynLib( const std::string& name );
        ~DynLib();
        void load();
        void unload();
const std::string& getName(void) const { return mName; }
        void* getSymbol( const std::string& strName ) const throw();
    protected:
        DYNLIB_HANDLE m_hInst;
    };
}

#endif




and the cpp file:

Code: [Select]

#include "DynLib.h"
#include <iostream>
#if defined(SFML_SYSTEM_WINDOWS)
#   define WIN32_LEAN_AND_MEAN
#   include <windows.h>
#endif

#if defined(SFML_SYSTEM_MACOS)
#   include "macPlugins.h"
#endif

namespace sf
{
    DynLib::DynLib( const std::string& name )
    {
        mName = name;
        m_hInst = NULL;
    }
    DynLib::~DynLib()
    {
    }
    void DynLib::load()
    {
std::string name = mName;
#if defined(SFML_SYSTEM_LINUX)
        // dlopen() does not add .so to the filename, like windows does for .dll
        if (name.substr(name.length() - 3, 3) != ".so")
           name += ".so";
#endif
        m_hInst = (DYNLIB_HANDLE)DYNLIB_LOAD( name.c_str() );
        if( !m_hInst )
            std::cerr << "Could not load dynamic library " << mName << ".  System Error: " << dynlibError() << "DynLib::load" ;
    }

    void DynLib::unload()
    {
        if( DYNLIB_UNLOAD( m_hInst ) )
{
            std::cerr << "Could not unload dynamic library " << mName << ".  System Error: " << dynlibError() << "DynLib::unload";
}

    }

    void* DynLib::getSymbol( const std::string& strName ) const throw()
    {
        return (void*)DYNLIB_GETSYM( m_hInst, strName.c_str() );
    }
    std::string DynLib::dynlibError( void )
    {
#if defined(SFML_SYSTEM_WINDOWS)
        LPVOID lpMsgBuf;
        FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL);
        std::string ret = (char*)lpMsgBuf;
        LocalFree( lpMsgBuf );
        return ret;
#elif defined(SFML_SYSTEM_LINUX)
        return std::string(dlerror());
#elif defined(SFML_SYSTEM_MACOS)
        return std::string(mac_errorBundle());
#else
        return std::string("");
#endif
    }

}



so now i saved you all 15min of work ;)
Title: DLL convenience wrapper
Post by: Core Xii on October 16, 2008, 05:06:22 am
If it works, thanks. I couldn't do this myself. OgreDynLib.h includes OgrePrerequisites.h, which in turn includes OgrePlatform.h, OgreStdHeaders.h and OgreMemoryAllocatorConfig.h; Which include a bunch of STL headers. Got much too entangled for me to handle.
Title: DLL convenience wrapper
Post by: zarka on October 16, 2008, 10:44:54 am
Quote from: "Core Xii"
If it works, thanks. I couldn't do this myself. OgreDynLib.h includes OgrePrerequisites.h, which in turn includes OgrePlatform.h, OgreStdHeaders.h and OgreMemoryAllocatorConfig.h; Which include a bunch of STL headers. Got much too entangled for me to handle.


You should never try to dig that deep at once. start by checking out the class definition and see what the class actually uses. it is quite obvious that this class uses very little of Ogres internal functions. oh and yes it works i played with it some more yesterday and as an example loaded up the functions SDL_SetError and SDL_GetError from sdl.dll and used called them and it worked :)

here is the way i did it:
1. fix obvius errors (like removing Ogre includes, inheritances, and preprocessor commands)
2. hit compile
3. fix errors (like Ogre::String and ogre log/exceptions)
4. goto 2 until no more errors
5. tests it out and fix runtime errors(actualy i never got any runtime errors.. i just had to figure out how to casts the void* returned from getSymbol to a usable function pointer)

common errors was
1. platform defines (sfml has these in it's system lib so i just switched to those
2. String (is a ogre typedef of std::string) so i replaced all String with std::string
3. exchanged all ogre exceptions and logger calls to std::cerr calls
4. it inherits from some kind of ogre allocator... which i do not know what it does and have no intentions to find out... so it got removed completely.. and i have noticed no errors.

learning how to refactor other peoples code is a great skill to know, especially if you want to start working as a programmer. (since changing/fixing other peoples code is what you will most likely do all day long ;) )
Title: DLL convenience wrapper
Post by: Core Xii on October 16, 2008, 11:15:21 am
I imagine. But I'm not really a programmer, more like an engineer. My talent lies in creating stuff, not understanding others' :roll:

Anyway, thank you for assisting me. I'm hoping a similar class finds its way into SFML so it'll be readily usable right away (not that there's anything wrong with your implementation). Until then, might just use this 8)