Вопросы по использованию FFI
- John Doe
- Бюрократ
- Posts: 13847
- Joined: Wed 27 Apr, 2005 20:42
- Has thanked: 73 times
- Been thanked: 428 times
- Contact:
Вопросы по использованию FFI
FFI — одна из стандартных библиотек luajit.
Позволяет из Lua кода вызывать внешние C-функции и использовать структуры данных C.
В данной теме задаём вопросы по использованию FFI
Заготовка для документации: viewtopic.php?f=57&t=8418&p=147610#p147610
Примеры готовых скриптов:
Предупреждение: viewtopic.php?p=147610#p147610
Позволяет из Lua кода вызывать внешние C-функции и использовать структуры данных C.
В данной теме задаём вопросы по использованию FFI
Заготовка для документации: viewtopic.php?f=57&t=8418&p=147610#p147610
Примеры готовых скриптов:
Предупреждение: viewtopic.php?p=147610#p147610
- John Doe
- Бюрократ
- Posts: 13847
- Joined: Wed 27 Apr, 2005 20:42
- Has thanked: 73 times
- Been thanked: 428 times
- Contact:
Получение привилегий backup/restore
Latest post of the previous page:
Совсем памяти нет, уже ведь обсуждали http://forum.farmanager.com/viewtopic.p ... 56#p111556, http://forum.farmanager.com/viewtopic.p ... 01#p115201
- John Doe
- Бюрократ
- Posts: 13847
- Joined: Wed 27 Apr, 2005 20:42
- Has thanked: 73 times
- Been thanked: 428 times
- Contact:
Получение привилегий backup/restore
По-моему вопрос о другом.
Code: Select all
Utf8ToUtf16(str.."\0")
-
- Posts: 6834
- Joined: Thu 23 Mar, 2006 21:36
- Location: Israel
- Has thanked: 41 times
- Been thanked: 530 times
Получение привилегий backup/restore
Вам правильно казалось. Результат будет содержать \0\0 в конце (и ещё один \0 внутренней репрезентации).
- Smitis
- Posts: 1709
- Joined: Fri 18 Mar, 2005 12:51
- Location: Питер
- Has thanked: 23 times
- Been thanked: 55 times
Получение привилегий backup/restore
Кажется понял. Ноль есть в памяти, но он не считается частью строки, поэтому строковые функции, в том числе Utf8ToUtf16, его игнорируют. Что бы получить ноль в UTF-16 его надо ЯВНО добавить в строку. Можно добавить 0 в win.Utf8ToUtf16(str.."\0"), тогда в конце буфера будет ТРИ нулевых байта или win.Utf8ToUtf16(str).."\0", тогда будет ДВА нулевых байта, что в любом случае для работы юникодных функций достаточно.
Last edited by Smitis on Fri 08 Sep, 2017 21:56, edited 2 times in total.
Разум когда-нибудь победит.
- DrKnS
- Posts: 6114
- Joined: Thu 04 Aug, 2005 06:44
- Location: Kyiv
- Has thanked: 12 times
- Been thanked: 426 times
-
- Posts: 6834
- Joined: Thu 23 Mar, 2006 21:36
- Location: Israel
- Has thanked: 41 times
- Been thanked: 530 times
Вопросы по использованию FFI
Это сделано для удобства внутренних операций LuaFAR. Там же двумя строчками ниже выставляется выходной размер, и он используется при формировании строки, выдаваемой "наружу". Другими словами, в функциях Lua-интерфейса этот \0 появляться не должен.
- DrKnS
- Posts: 6114
- Joined: Thu 04 Aug, 2005 06:44
- Location: Kyiv
- Has thanked: 12 times
- Been thanked: 426 times
Вопросы по использованию FFI
Да, действительно - по документации lua_pushlstring "makes (or reuses) an internal copy of the given string", теряя этот \0. Печально.
-
- Posts: 6834
- Joined: Thu 23 Mar, 2006 21:36
- Location: Israel
- Has thanked: 41 times
- Been thanked: 530 times
Вопросы по использованию FFI
Печально, что главный автор Lua не согласился добавлять два "служебных" \0 вместо одного. (Причина, полагаю в том, что для него UTF-16 - экзотика, не стоящая внимания).
Добавить один (или сколько угодно) нулевых байтов к результату в LuaFAR совсем не проблема, но это будет некорректное преобразование.
Как вариант, можно было бы сделать дополнительные функции c Z ("zero") в конце имени, например
Добавить один (или сколько угодно) нулевых байтов к результату в LuaFAR совсем не проблема, но это будет некорректное преобразование.
Как вариант, можно было бы сделать дополнительные функции c Z ("zero") в конце имени, например
Utf8ToUtf16Z
.- John Doe
- Бюрократ
- Posts: 13847
- Joined: Wed 27 Apr, 2005 20:42
- Has thanked: 73 times
- Been thanked: 428 times
- Contact:
Вопросы по использованию FFI
К сожалению это мало чем отличается от того, чтобы добавить ноль конкатенацией с аргументом функции..
- John Doe
- Бюрократ
- Posts: 13847
- Joined: Wed 27 Apr, 2005 20:42
- Has thanked: 73 times
- Been thanked: 428 times
- Contact:
Вопросы по использованию FFI
Давно было, и тогда мне почему то не пришло в голову решение на Lua, типа такого:John Doe wrote: ↑Tue 25 Feb, 2014 12:56 Ещё вопрос.
В буфере из примера выше находится C-строка неизвестной длины.
Как лучше всего перевести её в lua-строку?
Очевидно надо использовать ffi.string, но поскольку длина заранее неизвестна, то возможны варианты
- объявить и использоватьC.lstrlenW
- перевести в строку весь буфер, и использоватьmatch"(.-)%z"
Code: Select all
local wchar = ffi.cast("wchar_t*",ptr)
local len = 0
while wchar[len]~=0 do len = len+1 end
Last edited by John Doe on Wed 13 Sep, 2017 18:00, edited 1 time in total.
- John Doe
- Бюрократ
- Posts: 13847
- Joined: Wed 27 Apr, 2005 20:42
- Has thanked: 73 times
- Been thanked: 428 times
- Contact:
Вопросы по использованию FFI
Code: Select all
local ptr = ffi.new("char[?]",100,win.Utf8ToUtf16"test")
Из документации вроде бы следует, что ffi.new заполняет созданый массив нулями.
Однако в случае, когда в качестве инициализатора выступает строка, меньшая по длине, остаток видимо не обнуляется.The elements of an array are initialized, starting at index zero. If a single initializer is given for an array, it's repeated for all remaining elements. This doesn't happen if two or more initializers are given: all remaining uninitialized elements are filled with zero bytes.
В документации этот частный случай не рассматривается, сказано только в общем:
Byte arrays may also be initialized with a Lua string. This copies the whole string plus a terminating zero-byte. The copy stops early only if the array has a known, fixed size.
-
- Posts: 6834
- Joined: Thu 23 Mar, 2006 21:36
- Location: Israel
- Has thanked: 41 times
- Been thanked: 530 times
Вопросы по использованию FFI
На мой взгляд, сказано исчерпывающе ("This copies the whole string plus a terminating zero-byte").
- John Doe
- Бюрократ
- Posts: 13847
- Joined: Wed 27 Apr, 2005 20:42
- Has thanked: 73 times
- Been thanked: 428 times
- Contact:
Вопросы по использованию FFI
Меня ввело в заблужнение то, что непосредственно перед этим сказано: all remaining uninitialized elements are filled with zero bytes.
А так да, не спорю.
А так да, не спорю.
- John Doe
- Бюрократ
- Posts: 13847
- Joined: Wed 27 Apr, 2005 20:42
- Has thanked: 73 times
- Been thanked: 428 times
- Contact:
Вопросы по использованию FFI
Заготовка для документации:
0. Использование ffi (помимо усвоения документации библиотеки) в целом требует определённой квалификации, понимания работы вызываемых функций, осторожного обращения с памятью, и т.п.
Ниже следуют только дополнения, описывающие особенности использования ffi в фаре
1. Любое определение, сделанное посредством
Переопределить его невозможно: будет действовать определение, сделанное первым.
1.1. Определение, сделанное в одном скрипте будет действовать для всех, поэтому важно чтобы определения были корректными.
1.2. В случае изменения определения на несовместимое потребуется перезагрузить плагин (или фар).
2. В отличии от переопределения функций, попытка переопределения констант и именованных(?) структур ещё и вызывает ошибку времени выполнения, поэтому следует оборачивать вызов в pcall:
2.1. Следует учитывать, что "переопределение" неизбежно, это вполне штатная ситуация: например при перезагрузке макросов, или при использовании определений в независимых скриптах.
3. Для удобства luamacro при старте загружает файл winapi.lua, содержащий определения типов, часто используемых в winapi.
4. ???
Работа со строками, с юникодом, передача параметра по ссылке или значению (_OUT_/_IN_ в msdn) это то, что абсолютно необходимо понимать при работе с ffi.
Прочитав тему с начала можно найти ответы на множество вопросов.
Если же вы не готовы тратить своё время на то чтобы во всём разобраться, то и начинать не стоит.
Todo: задокументировать нюансы, имеющие значение для распространённых задач:
- работа со строками, завершающий \0
- получение указателей/хэндлов, ...
- ограничение типов на 32бита: viewtopic.php?p=119951#p119951
0. Использование ffi (помимо усвоения документации библиотеки) в целом требует определённой квалификации, понимания работы вызываемых функций, осторожного обращения с памятью, и т.п.
Ниже следуют только дополнения, описывающие особенности использования ffi в фаре
1. Любое определение, сделанное посредством
ffi.cdef
, действует до конца сеанса.Переопределить его невозможно: будет действовать определение, сделанное первым.
1.1. Определение, сделанное в одном скрипте будет действовать для всех, поэтому важно чтобы определения были корректными.
1.2. В случае изменения определения на несовместимое потребуется перезагрузить плагин (или фар).
2. В отличии от переопределения функций, попытка переопределения констант и именованных(?) структур ещё и вызывает ошибку времени выполнения, поэтому следует оборачивать вызов в pcall:
2.1. Следует учитывать, что "переопределение" неизбежно, это вполне штатная ситуация: например при перезагрузке макросов, или при использовании определений в независимых скриптах.
3. Для удобства luamacro при старте загружает файл winapi.lua, содержащий определения типов, часто используемых в winapi.
4. ???
Работа со строками, с юникодом, передача параметра по ссылке или значению (_OUT_/_IN_ в msdn) это то, что абсолютно необходимо понимать при работе с ffi.
Прочитав тему с начала можно найти ответы на множество вопросов.
Если же вы не готовы тратить своё время на то чтобы во всём разобраться, то и начинать не стоит.
Todo: задокументировать нюансы, имеющие значение для распространённых задач:
- работа со строками, завершающий \0
- получение указателей/хэндлов, ...
- ограничение типов на 32бита: viewtopic.php?p=119951#p119951
Last edited by John Doe on Sat 12 May, 2018 16:50, edited 1 time in total.
-
- Posts: 6834
- Joined: Thu 23 Mar, 2006 21:36
- Location: Israel
- Has thanked: 41 times
- Been thanked: 530 times
- Smitis
- Posts: 1709
- Joined: Fri 18 Mar, 2005 12:51
- Location: Питер
- Has thanked: 23 times
- Been thanked: 55 times
Вопросы по использованию FFI
В подавляющем большинстве случаев достаточно убрать имя структуры
Code: Select all
ffi.cdef [[
typedef struct { // _CONSOLE_SELECTION_INFO
DWORD dwFlags;
COORD dwSelectionAnchor;
SMALL_RECT srSelection;
} CONSOLE_SELECTION_INFO, *PCONSOLE_SELECTION_INFO;
]]
Разум когда-нибудь победит.