Page 3 of 15

Вопросы по использованию FFI

Posted: Tue 21 May, 2013 20:20
by John Doe
FFI — одна из стандартных библиотек luajit.
Позволяет из Lua кода вызывать внешние C-функции и использовать структуры данных C.
В данной теме задаём вопросы по использованию FFI

Примеры готовых скриптов:

Предупреждение: viewtopic.php?p=147610#p147610

Re: ffi.C и unicode/multibyte ... string

Posted: Tue 17 Dec, 2013 18:03
by EGez

Latest post of the previous page:

HaRT wrote:Машина машине рознь. На многих RISC-архитектурах у char* и short* почти наверняка будет разное выравнивание, что чревато в лучшем случае просадкой производительности, а в типичном — “unaligned” exception. И да, некоторые из таких машин работают (работали?) под управлением тех или иных Windows.
Ну, совсем экзотикой можно принебречь...

Re: Вопросы по использованию FFI

Posted: Mon 24 Feb, 2014 15:41
by John Doe
Хотел составить функцию для превращения строки Lua в указатель, для передачи входных параметров в разные WinAPI-функции.
Сделал, работает:

Code: Select all

local function str2p(str)
  return ffi.cast("void*",win.Utf8ToUtf16(str .. '\0'))
end
Но перечитав тему засомневался, ведь результат win.Utf8ToUtf16 при выходе из функции становится мусором?
С другой стороны, полученный указатель и не требуется долго хранить...

В общем, на первой странице похожий пример рассматривался, решили что нельзя.
Если только не сохранить результат win.Utf8ToUtf16 в актуальную переменную. Или использовать ffi.new/ffi.copy

Хотя тогда я несовсем понимаю, почему в другом примере на первой странице делается так:

Code: Select all

local PluginId = ffi.cast("const GUID*", win.Uuid("4EBBEFC8-2084-4B7F-94C0-692CE136894D"))
local MenuId = ffi.cast("const GUID*", win.Uuid("6C47D27E-3E7E-4C65-916D-E1B1A31527AD"))
--пропущено 10 строк кода
psi.Menu(PluginId,MenuId,-1,-1,0,0,nil,nil,nil,nil,nil,items,N)
Разве тут есть гарантия, что данные доживут до момента их использования?

И последний момент: всегда ли корректно кастить в "void*", не разделяя что там на самом деле требуется принимающим функциям
(const wchar_t* / wchar_t* / char* / и т.д.) ?

Re: Вопросы по использованию FFI

Posted: Mon 24 Feb, 2014 16:45
by Shmuel
ffi.cast от "незакреплённой" величины - это скорее всего баг. То, что он не всегда проявляется, тоже понятно. Чтобы стимулировать проявление бага, можно вызвать пару раз collectgarbage("collect") между получением и использованием.

Пример с гуидом - да, видимо баг.

ffi.cast("void*", value) для передачи функциям Windows API / Far API корректен, если value указывает на то, что функция ожидает получить.

Re: Вопросы по использованию FFI

Posted: Tue 25 Feb, 2014 11:22
by John Doe
Спасибо.

А этот код можно ли заменить на ?
Есть тут какие-то грабли?

И правильно ли я понимаю что ffi.new("wchar_t[?]",BufferLength/2) это то же самое что ffi.new("char[?]",BufferLength)
Т.е. по большому счёту тип не важен, главное выделять BufferLength/ffi.sizeof(type)?

Re: Вопросы по использованию FFI

Posted: Tue 25 Feb, 2014 11:55
by HaRT
John Doe wrote:правильно ли я понимаю что ffi.new("wchar_t[?]",BufferLength/2) это то же самое что ffi.new("char[?]",BufferLength)[...]?
Не знаю, как там в Lua/FFI, а в Си/Си++ это будет корректно только на конкретных платформах. На других же платформах значение Пи может достигать четырёх размер sizeof(wchar_t) может заметно отличаться.

Re: Вопросы по использованию FFI

Posted: Tue 25 Feb, 2014 12:08
by John Doe
HaRT
Потому я и указал что в общем случае зависит от sizeof.
Но на тех платформах, на которых вообще возможен запуск фара, этим можно пренебречь.
Во всяком случае такой вывод я делаю из примеров кода специалистов:
spell.lua wrote:

Code: Select all

local function ToWChar(str)
  str=win.Utf8ToUtf16(str)
  local result=ffi.new("wchar_t[?]",#str/2+1)
  ffi.copy(result,str)
  return result
end

Re: Вопросы по использованию FFI

Posted: Tue 25 Feb, 2014 12:31
by Shmuel
John Doe wrote:А этот код можно ли заменить на ?
Есть тут какие-то грабли?

И правильно ли я понимаю что ffi.new("wchar_t[?]",BufferLength/2) это то же самое что ffi.new("char[?]",BufferLength)
Т.е. по большому счёту тип не важен, главное выделять BufferLength/ffi.sizeof(type)?
1. Граблей не вижу, но не забывать о дополнительном нулевом символе в конце.
2. Правильно, при условии, что ф-ция API получит на вход тот тип указателя, с которым она объявлена (или void*).

Re: Вопросы по использованию FFI

Posted: Tue 25 Feb, 2014 12:43
by zg
John Doe wrote:Есть тут какие-то грабли?
потенциально есть грабли с выравниванием.

Re: Вопросы по использованию FFI

Posted: Tue 25 Feb, 2014 12:56
by John Doe
zg
Т.е. адрес, по которому находится lua-строка, может прийтись не на начало машинного слова?
Выходит не стоит так делать.

Ещё вопрос.
В буфере из примера выше находится C-строка неизвестной длины.
Как лучше всего перевести её в lua-строку?
Очевидно надо использовать ffi.string, но поскольку длина заранее неизвестна, то возможны варианты
- объявить и использовать C.lstrlenW
- перевести в строку весь буфер, и использовать match"(.-)%z"

Почему-то кажется что должен быть более изящный способ.

Re: Вопросы по использованию FFI

Posted: Tue 25 Feb, 2014 18:17
by zg
John Doe wrote:Т.е. адрес, по которому находится lua-строка, может прийтись не на начало машинного слова?
в теории, да. на практике, наверное, нет. но кто ж его знает, что случится завтра.
John Doe wrote:- объявить и использовать C.lstrlenW

Почему-то кажется что должен быть более изящный способ.
я так делал в спелере, вроде даже что-то обсуждали тогда, и типа нет вариантов проще.

Re: Вопросы по использованию FFI

Posted: Tue 25 Feb, 2014 23:50
by John Doe
zg wrote:
John Doe wrote:Т.е. адрес, по которому находится lua-строка, может прийтись не на начало машинного слова?
в теории, да. на практике, наверное, нет. но кто ж его знает, что случится завтра.
Значит и пример с первой страницы не полностью надёжен?
  1. local text = win.Utf8ToUtf16(str)
  2. item.Text = ffi.cast("const wchar_t*", text)
Shmuel wrote:ffi.cast от "незакреплённой" величины - это скорее всего баг.
Нашёл в picture.lua:204 такой код:

Code: Select all

      local delayraw=ffi.cast("PropertyItem*",ffi.new("char[?]",delaysize[0]))

Re: Вопросы по использованию FFI

Posted: Wed 26 Feb, 2014 12:15
by zg
John Doe wrote:Значит и пример с первой страницы не полностью надёжен?
вопрос в том, как работает аллокатор строк и ffi.new. возможно там такое выравнивание, что хватит всем.
John Doe wrote:Нашёл в picture.lua:204 такой код:
спасибо, поправил.
update:
тут пишут, что «8 byte alignment is guaranteed» для ffi.new.

Re: Вопросы по использованию FFI

Posted: Sun 02 Mar, 2014 07:46
by John Doe
Возможно ли через ffi как-то воспользоваться C-функциями far api?

Re: Вопросы по использованию FFI

Posted: Sun 02 Mar, 2014 08:09
by Shmuel
John Doe wrote:Возможно ли через ffi как-то воспользоваться C-функциями far api?
Да, для этого даже добавлен файл LuaMacro\farapi.lua.
Для получения указателя на PluginStartupInfo есть ф-ция far.CPluginStartupInfo, нужно cделать ffi.cast() от результата её вызова.

Re: Вопросы по использованию FFI

Posted: Sun 02 Mar, 2014 11:23
by John Doe
Не могу сообразить как этим воспользоваться.
При попытке ffi.cast("PluginStartupInfo*",far.CPluginStartupInfo()) получаю ошибку declaration specifier expected near 'PluginStartupInfo'

Re: Вопросы по использованию FFI

Posted: Sun 02 Mar, 2014 11:41
by Shmuel
Попробуйте "struct PluginStartupInfo*".