создание структуры обратного вызова для передачи в LuaJIT FFI

Итак, сначала я загружаю нужную мне DLL

local ffi = require("ffi")
local theDLL = ffi.load("thisDLL")

в ffi cdef у меня есть два разных типа структур

ffi.cdef [[
    typedef struct StructSession StructSession;
    typedef struct {
        /*
        * begin_proj callback
        */
        bool (__cdecl *begin_proj)(char *proj);

        /*
        * save_proj_state
        */
        bool (__cdecl *save_proj_state)(unsigned char **buffer, int *len);
    } StructCallbacks;

У меня тоже есть эта функция в cdef

__declspec(dllexport) int __cdecl start_session(StructSession **session,
                                                           StructCallbacks *cb);

Теперь я хотел бы назвать эту функцию

print(theDLL.start_session(a,b))

Очевидно, что переменные a и b являются заполнителями, вопрос в том, как передать структуры, которые нужны функции? И скажем, мы получили работу StructSession, будет ли возможность обратного вызова функции ВНУТРИ LuaJIT для StructCallbacks?


person theman    schedule 30.05.2014    source источник


Ответы (1)


Создать StructCallbacks легко; вы можете создать его с помощью ffi.new и создать обратные вызовы FFI для полей (см. семантику FFI для получения информации об обратных вызовах).

Создать StructSession сложнее, поскольку это непрозрачный тип, но он не сильно отличается от того, как вы это делали бы в C.

Вот как вы создадите его на C:

StructSession* S = NULL;
start_session(*S, foo);

Обратите внимание на то, что вы не выделяете напрямую StructSession. Вместо этого вы выделяете указатель на одну и позволяете start_session выделять фактическую структуру.

Итак, теперь мы переводим это в код LuaJIT:

local S = ffi.new("StructSession*")
lib.start_session(getPointer(S), foo) -- getPointer should take the pointer of S, but...

... FFI не предоставляет никакого способа получить указатель объекта (это сделано намеренно; это позволяет проводить оптимизацию).

Так как же нам получить указатель на StructSession? Вспомните, что массивы можно преобразовать в указатели, и мы можем получить к ним доступ через FFI. Поэтому вместо этого мы создаем однослотовый массив указателей и передаем его start_session:

local S_slot = ffi.new("StructSession*[1]")
lib.start_session(S_slot, foo)
local S = S_slot[0]

И теперь у вас есть объект StructSession.

person Colonel Thirty Two    schedule 31.05.2014