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

Столкнулись с проблемой в использовании макросов? Здесь можно получить помощь.
User avatar
John Doe
Бюрократ
Posts: 12656
Joined: Wed 27 Apr, 2005 20:42
Has thanked: 35 times
Been thanked: 270 times

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

Post by John Doe »

FFI — одна из стандартных библиотек luajit.
Позволяет из Lua кода вызывать внешние C-функции и использовать структуры данных C.
В данной теме задаём вопросы по использованию FFI

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

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

Shmuel
Posts: 6031
Joined: Thu 23 Mar, 2006 21:36
Location: Israel
Has thanked: 27 times
Been thanked: 294 times

Re: Ликбез по Lua

Post by Shmuel »

Latest post of the previous page:

Я в своё время просил Роберто (в форуме Lua, можно найти) добавлять два нуля к стрингам вместо одного, но он не пошёл на это.

User avatar
zg
zero-gravity
Posts: 5715
Joined: Tue 15 Mar, 2005 17:36
Location: riga
Been thanked: 134 times
Contact:

Re: luajit в фаре

Post by zg »

Shmuel wrote:В своих библиотеках можно перед вызовом ffi.cdef проверить, определена ли та или иная константа.
а как?

Shmuel
Posts: 6031
Joined: Thu 23 Mar, 2006 21:36
Location: Israel
Has thanked: 27 times
Been thanked: 294 times

luajit в фаре

Post by Shmuel »

zg wrote:а как?
Например, так:
  1. local ffi = require "ffi"
  2. if pcall(ffi.sizeof, "FFI_FARAPI_DEFINED") then return end
  3. ffi.cdef "typedef int FFI_FARAPI_DEFINED"

Acerbic
Posts: 80
Joined: Wed 07 Apr, 2010 12:30
Been thanked: 2 times

Re: luajit в фаре

Post by Acerbic »

Shmuel wrote: LuaJIT FFI рассматривает переопределение статических констант и enum'ов как ошибку. На повторное определение функций почему-то не жалуется.
Это в С такая фишка, что объявление и определение - разные вещи, ЕМНИП. Определения повторять нельзя, объявления можно. Для функций заголовок без тела считается только объявлением, а константы и переменные (даже не инициализированные) считаются определениями, если нет специального ключевого слова extern

Shmuel
Posts: 6031
Joined: Thu 23 Mar, 2006 21:36
Location: Israel
Has thanked: 27 times
Been thanked: 294 times

Re: luajit в фаре

Post by Shmuel »

Acerbic wrote:Это в С такая фишка, что объявление и определение - разные вещи, ЕМНИП. Определения повторять нельзя, объявления можно. Для функций заголовок без тела считается только объявлением, а константы и переменные (даже не инициализированные) считаются определениями, если нет специального ключевого слова extern
Да, это так, но при использовании в Lua доставляет неудобства: нельзя (без спец-приседаний) запустить скрипт более 1 раза, нельзя перезагрузить модуль.

EGez
Posts: 144
Joined: Thu 04 Oct, 2012 13:53
Location: Hamburg, DE
Has thanked: 2 times
Been thanked: 2 times

ffi.C и unicode/multibyte ... string

Post by EGez »

Что-то никак не получается через FFI протолкнуть кириллический текст без потерь, уже даже к методам научного тыка прибегнуть пришлось ... :(

На примере: MessageBoxW(HWND, LPCWSTR, LPCWSTR, UINT);

Пока пришел к следующему, но в конце текста сообщения мусор, как правильно с ним работать?
  1. -- file encoding UTF-8/65001
  2.  
  3. local ffi = require("ffi")
  4. local C = ffi.C
  5.  
  6. ffi.cdef[[
  7. int MessageBoxA(void *w, const char *txt, const char *cap, int type);
  8. int MessageBoxW(void *w, const wchar_t *txt, const wchar_t *cap, int type);
  9. ]]
  10.  
  11. -- MessageBoxW:
  12. -- 1. Китайский
  13. C.MessageBoxW(nil, 'Кириллический текст', 'AS IS', 1)
  14.  
  15. -- 2. Вроде работает, но в конце строк мусор
  16. C.MessageBoxW(nil, win.Utf8ToUtf16('Кириллический текст'), win.Utf8ToUtf16('Utf8ToUtf16'), 1)
  17.  
  18. -- 3. Снова китай
  19. C.MessageBoxW(nil, win.OemToUtf8('Кириллический текст'), win.OemToUtf8('OemToUtf8'), 1)
  20.  
  21.  
  22. -- MessageBoxA:
  23. -- 4. UTF-8 в ANSI кодировке
  24. C.MessageBoxA(nil, 'Кириллический текст', 'AS IS', 1)
Последний случай (MessageBoxA) у большинства из вас скорее всего будет работать, т.к. locale у вас "случайно" подходящая...

Благодарю

Abs
Posts: 67
Joined: Tue 27 Jul, 2010 12:14
Been thanked: 7 times

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

Post by Abs »

EGez wrote:-- 2. Вроде работает, но в конце строк мусор
C.MessageBoxW(nil, win.Utf8ToUtf16('Кириллический текст'), win.Utf8ToUtf16('Utf8ToUtf16'), 1)

Code: Select all

C.MessageBoxW(nil, win.Utf8ToUtf16('Кириллический текст\0'), win.Utf8ToUtf16('Utf8ToUtf16\0'), 1)
?

EGez
Posts: 144
Joined: Thu 04 Oct, 2012 13:53
Location: Hamburg, DE
Has thanked: 2 times
Been thanked: 2 times

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

Post by EGez »

Abs wrote:

Code: Select all

C.MessageBoxW(nil, win.Utf8ToUtf16('Кириллический текст\0'), win.Utf8ToUtf16('Utf8ToUtf16\0'), 1)
?
Спасибо, сработало.

Но меня терзают смутные сомнения: Почему jit их автоматически не завершает нулями при передаче в контекст c runtime? Это же стандарт в C/C++, именно поэтому мне и не пришла такая идея в голову.
Это workaround или стандартное поведение? Где-нибудь описано?

Спасибо

User avatar
zg
zero-gravity
Posts: 5715
Joined: Tue 15 Mar, 2005 17:36
Location: riga
Been thanked: 134 times
Contact:

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

Post by zg »

EGez wrote:Но меня терзают смутные сомнения: Почему jit их автоматически не завершает нулями при передаче в контекст c runtime?
а как он должен догадаться?

Shmuel
Posts: 6031
Joined: Thu 23 Mar, 2006 21:36
Location: Israel
Has thanked: 27 times
Been thanked: 294 times

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

Post by Shmuel »

EGez wrote:Но меня терзают смутные сомнения: Почему jit их автоматически не завершает нулями при передаче в контекст c runtime? Это же стандарт в C/C++, именно поэтому мне и не пришла такая идея в голову.
Это workaround или стандартное поведение? Где-нибудь описано?
LuaJIT обрабатывает то, что ему передано, и это правильно.

Данное поведение проистекает от того, что, в отличие от Си-строк, строки в Lua не содержат завершающего нуля (хотя во внутренностях Lua он имеется, но только один нулевой байт, а не два, как нужно для UTF-16).

EGez
Posts: 144
Joined: Thu 04 Oct, 2012 13:53
Location: Hamburg, DE
Has thanked: 2 times
Been thanked: 2 times

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

Post by EGez »

Shmuel wrote: LuaJIT обрабатывает то, что ему передано, и это правильно.

Данное поведение проистекает от того, что, в отличие от Си-строк, строки в Lua не содержат завершающего нуля (хотя во внутренностях Lua он имеется, но только один нулевой байт, а не два, как нужно для UTF-16).
Хм.. Я кажется понял в чем дело. Скорее дело не в том, что Lua не использует zero termination.
Поскольку Lua стринги свои не различает на широкие и узкие, ;-) в C runtime оно, похоже, передается как char[]/byte[] совершенно не задумываясь о семантике содержимого и все-таки завершенным одним \0 (т.к. char). Поэтому ANSI функции работают нормально... А функция же, которая получает от сего пойнтер параметром, ожидает, что это utf16 и интерпретирует его соответственно, ну и обламывается на одном \0.

Спасибо!

User avatar
John Doe
Бюрократ
Posts: 12656
Joined: Wed 27 Apr, 2005 20:42
Has thanked: 35 times
Been thanked: 270 times

ffi.C и unicode/multibyte ... string

Post by John Doe »

EGez wrote:Что-то никак не получается через FFI протолкнуть кириллический текст без потерь, уже даже к методам научного тыка прибегнуть пришлось ... :(

На примере: MessageBoxW(HWND, LPCWSTR, LPCWSTR, UINT);

Последний случай (MessageBoxA) у большинства из вас скорее всего будет работать, т.к. locale у вас "случайно" подходящая...

Благодарю
Что тут может быть не так?

Code: Select all

C:\APPs\Far3\lua51x.exe: C:\APPs\Far3\Profile\Macros\2check\ffi\MessageBoxW.lua:13: bad argument #2
to 'MessageBoxW' (cannot convert 'string' to 'const unsigned short *')
stack traceback:
        [C]: in function 'MessageBoxW'
        C:\APPs\Far3\Profile\Macros\2check\ffi\MessageBoxW.lua:13: in main chunk
        [C]: at 0x00407bbc
Проблема только с MessageBoxW, а MessageBoxA отрабатывает нормально

Shmuel
Posts: 6031
Joined: Thu 23 Mar, 2006 21:36
Location: Israel
Has thanked: 27 times
Been thanked: 294 times

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

Post by Shmuel »

John Doe wrote:Что тут может быть не так?

Code: Select all

C:\APPs\Far3\lua51x.exe: C:\APPs\Far3\Profile\Macros\2check\ffi\MessageBoxW.lua:13: bad argument #2
to 'MessageBoxW' (cannot convert 'string' to 'const unsigned short *')
stack traceback:
        [C]: in function 'MessageBoxW'
        C:\APPs\Far3\Profile\Macros\2check\ffi\MessageBoxW.lua:13: in main chunk
        [C]: at 0x00407bbc
В тексте ошибки ясно сказано, что не так. wchar_t - это unsigned short.
Почитайте несколько сообщений, начиная от http://forum.farmanager.com/viewtopic.p ... 45#p111545, там есть примеры.

User avatar
John Doe
Бюрократ
Posts: 12656
Joined: Wed 27 Apr, 2005 20:42
Has thanked: 35 times
Been thanked: 270 times

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

Post by John Doe »

В данном случае я не пытался освоить FFI, а всего лишь хотел запустить готовый пример из первого сообщения.
Автор представляет его как рабочий, поэтому мне показалось что у меня какая-то проблема с инсталляцией.

Shmuel
Posts: 6031
Joined: Thu 23 Mar, 2006 21:36
Location: Israel
Has thanked: 27 times
Been thanked: 294 times

ffi.C и unicode/multibyte ... string

Post by Shmuel »

Можно так:
  1. C.MessageBoxW(nil, ffi.cast("void*", win.Utf8ToUtf16('Кириллический текст\0')),
  2.    ffi.cast("void*", win.Utf8ToUtf16('Utf8ToUtf16\0')), 1)

EGez
Posts: 144
Joined: Thu 04 Oct, 2012 13:53
Location: Hamburg, DE
Has thanked: 2 times
Been thanked: 2 times

ffi.C и unicode/multibyte ... string

Post by EGez »

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

На самом деле у меня работающий пример выглядит так:
  1. -- file encoding UTF-8/65001
  2.  
  3. local ffi = require 'ffi'
  4. local C = ffi.C
  5.  
  6. local function utf16(str)
  7.     return win.Utf8ToUtf16(str .. '\0')
  8. end
  9.  
  10. ffi.cdef[[
  11. int MessageBoxW(void *w, const char *txt, const char *cap, int type);
  12. ]]
  13.  
  14. C.MessageBoxW(nil, utf16('Тут у нас сообщение (message)'), utf16('Тут у нас титель (title)'), 1)
Я конечно понимаю, что так делать не совсем чисто, но для машины-то без разницы, будь то char* byte* или short*.

Post Reply

Return to “Нужна помощь”