Question

I am having an issue with Luabind that I am unsure of how to fix without some over-simplified solution.

Luabind appears to only allow binding to functions using the __cdecl calling convention. In my current project all of the functionality exposed to extensions/plugins is exposed using __stdcall. This leaves me unable to bind the exposed objects directly and instead I have to make wrappers for the objects exposed. This would be fine but there are a lot of objects that would need to be wrapped.

For example, an object can look like this:

struct IObject
{
    void __stdcall SomeFunc1( void );
    void __stdcall SomeFunc2( const char* );
};

struct IObjectContainer
{
    IObject* __stdcall GetObject( int );
    IObject* __stdcall GetObject( const char* );
};

struct IObjectCore
{
    IObjectContainer* __stdcall GetObjectContainer();
};

I don't have the option of changing the entire projects calling convention currently so I am seeing if someone has a solution to perhaps patch Luabind to work with __stdcall functions. I am not the best with templates and with boost things, so I'm personally unsure where to even start trying to add the ability to use __stdcall functions.

For reference, I am using:

  • Lua 5.1.4
  • Luabind 0.9.1
  • VS2010

Both Lua and Luabind are stock latest versions of their rev. (Not using Lua 5.2 for project restriction reasons, but if there is a __stdcall fix for 5.2/Luabind I will gladly take that as well.)

I could only find a fix for a very old version of Luabind to do this but the patch floating on the net still for that does not line up with the current Luabind code at all.

If there is any other information needed feel free to ask.

Was it helpful?

Solution

Sadly due to inactivity and no further answers from more searching I spoke with the project developer and have gotten the entire project stripped of __stdcall. So the bindings all work fine now via __cdecl. Not the route I wanted to take but things are working as planned now.

OTHER TIPS

I faced the exact same problem when binding OpenGL (with GLEW functions) to Lua, and solved it using variadic templates.

Now if the function is global and you know its address in compile time, you can be good with something like this:

template<typename Signature>
struct wrap_known;

template<typename Ret, typename... Args>
struct wrap_known<Ret __stdcall (Args...)> {
    template <Ret __stdcall functor(Args...)>
    static Ret invoke(Args... arguments) {
        return functor(arguments...);
    }
};

// I know using macro is generally a bad idea but it's just shorter
#define wrap(f) wrap_known<decltype(f)>::invoke<f>

and then, when binding, use the macro like this:

luabind::def("Clear", wrap(glClear)),
luabind::def("Vertex4f", wrap(glVertex4f))

However, in your case, we have a bunch of member functions and not globals like above. Here is the code for wrapping member functions with __stdcall calling convention:

template<typename Signature>
struct wrap_mem;

template<typename Sub, typename Ret, typename... Args>
struct wrap_mem<Ret(__stdcall Sub::*) (Args...)> {

    template <Ret(__stdcall Sub::*functor) (Args...)>
    static Ret invoke(Sub* subject, Args... arguments) {
        return (subject->*functor)(arguments...);
    }
};

#define wrap_member(f) wrap_mem<decltype(f)>::invoke<f>

Use it like this:

struct A {
    int __stdcall my_method(double b) {
        return 2;
    }
};

// ...
luabind::class_<A>("A")
.def("my_method", wrap_member(&A::my_method))

Sometimes, however, you are not that lucky to know the function's address in compile time, and this happens with GLEW for example. For functions like glUniform*f, glGetUniformLocation, the "wrap" macro will not work, so I made another version for wrapping functions known at runtime:

template<typename Signature>
struct wrap_unknown;

template<typename Ret, typename... Args>
struct wrap_unknown<Ret (__stdcall*) (Args...)> {
    template <Ret (__stdcall** functor)(Args...)>
    static Ret invoke(Args... arguments) {
        return (**functor)(arguments...);
    }
};

#define wrap_ptr(f) wrap_unknown<decltype(f)>::invoke<&f>

(if above code scares you, it is actually a good sign)

Now you can bind GLEW functions like this:

luabind::def("Uniform4f", wrap_ptr(glUniform4f)),
luabind::def("GetUniformLocation", wrap_ptr(glGetUniformLocation))

Just don't ask me to write another version for binding pointers to members known at runtime :)

If you don't want to use C++11 for some reason, here you can find out how to pass function arguments and return value as template parameters in C++03.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top