【问题标题】:Luabind calling convention issuesLuabind 调用约定问题
【发布时间】:2012-11-08 11:51:24
【问题描述】:

我在使用 Luabind 时遇到问题,如果没有一些过于简化的解决方案,我不确定如何解决。

Luabind 似乎只允许使用__cdecl 调用约定绑定到函数。在我当前的项目中,所有暴露给扩展/插件的功能都是使用__stdcall 暴露的。这使我无法直接绑定暴露的对象,而是必须为暴露的对象制作包装器。这很好,但有很多对象需要包装。

例如,一个对象可以如下所示:

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();
};

我目前没有更改整个项目调用约定的选项,因此我正在查看是否有人有解决方案来修补 Luabind 以使用 __stdcall 函数。我在模板和增强功能方面不是最好的,所以我个人不确定从哪里开始尝试添加使用__stdcall 函数的能力。

作为参考,我正在使用:

  • Lua 5.1.4
  • Luabind 0.9.1
  • VS2010

Lua 和 Luabind 都是其版本的最新版本。 (出于项目限制的原因,不使用 Lua 5.2,但如果有针对 5.2/Luabind 的 __stdcall 修复,我也很乐意接受。)

我只能找到一个非常旧版本的 Luabind 的修复程序来执行此操作,但网上流传的补丁仍然与当前的 Luabind 代码完全不符。

如果需要任何其他信息,请随时询问。

【问题讨论】:

  • 您可以将这些对象包装到另一个调用约定并绑定它们
  • 我知道,我已经在帖子中说明了这一点。我明确表示我会尽量避免这样做。
  • 抱歉跳过了。不过,无论如何,您都必须在绑定上投入时间...
  • 嗯..你看我的解决方案了吗?
  • 我不再需要解决这个问题了,不过谢谢。

标签: lua calling-convention luabind


【解决方案1】:

遗憾的是,由于不活动并且没有更多的搜索得到进一步的答案,我与项目开发人员进行了交谈,并且整个项目都被剥夺了 __stdcall。因此,现在通过 __cdecl 绑定都可以正常工作。不是我想走的路线,但现在一切都在按计划进行。

【讨论】:

    【解决方案2】:

    我在将 OpenGL(使用 GLEW 函数)绑定到 Lua 时遇到了完全相同的问题,并使用可变参数模板解决了这个问题。

    现在,如果函数是全局的,并且您在编译时知道它的地址,那么您可以使用以下方法:

    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>
    

    然后,在绑定时,像这样使用宏:

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

    但是,在您的情况下,我们有一堆成员函数,而不是像上面那样的全局函数。 以下是使用 __stdcall 调用约定包装成员函数的代码:

    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>
    

    像这样使用它:

    struct A {
        int __stdcall my_method(double b) {
            return 2;
        }
    };
    
    // ...
    luabind::class_<A>("A")
    .def("my_method", wrap_member(&A::my_method))
    

    但是,有时,在编译时知道函数的地址并不那么幸运,例如 GLEW 就会发生这种情况。对于 glUniform*f、glGetUniformLocation 等函数,“wrap”宏不起作用,所以我制作了另一个版本,用于在运行时包装函数:

    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>
    

    (如果上面的代码吓到你了,其实是个好兆头)

    现在您可以像这样绑定 GLEW 函数:

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

    只是不要让我编写另一个版本来将指针绑定到运行时已知的成员:)

    如果您出于某种原因不想使用 C++11,请here you can find out how to pass function arguments and return value as template parameters in C++03

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-11-06
      • 1970-01-01
      • 1970-01-01
      • 2011-09-23
      • 2010-12-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多