Руби Нуби:Как установить строковое значение в структуре FFI
Вопрос
У меня возникли некоторые проблемы с настройкой структуры FFI в Ruby.Я хочу передать указатель на строку C, установив свойство строки в объекте FFI::Struct:
class SpSessionConfig < FFI::Struct
layout :api_version, :int,
:cache_location, :string,
:settings_location, :string,
:application_key, :pointer,
:application_key_size, :int,
:user_agent, :string,
:sp_session_callbacks, :pointer,
:user_data, :pointer
end
end
sessionConf = SpotifyLibrary::SpSessionConfig.new()
puts sessionConf # => '#<SpotifyLibrary::SpSessionConfig:0x9acc00c>'
sessionConf[:api_version] = 1
puts "Api Version: #{sessionConf[:api_version]}"
myTempDir = "tmp"
sessionConf[:cache_location] = myTempDir # !Error!
Но когда я запускаю код, я получаю эту ошибку:
jukebox.rb:44:in `[]=': Cannot set :string fields (ArgumentError)
from jukebox.rb:44:in `<main>'
Так что я действительно не знаю, куда идти дальше.
Кроме того, если вам известна какая-либо хорошая документация или учебные пособия по этой теме, пожалуйста, оставьте ответ!До сих пор я нашел вики-документацию по Проект Кенайочень полезно, но чем больше, тем лучше!
Спасибо!
Я попытался объявить элементы строковых данных как [:char, 5], но это привело к еще одной ошибке:
jukebox.rb:44:in `put': put not supported for FFI::StructLayoutBuilder::ArrayField_Signed8_3 (ArgumentError)
from jukebox.rb:44:in `[]='
from jukebox.rb:44:in `<main>
Есть хорошее предложение попробовать тип указателя памяти, и я попробую это сегодня после работы.
Решение
FFI автоматически отклоняет строки настроек.Попробуйте изменить его с :string на :char_array, как указано в разделе эта страница:
:char_array — используется ТОЛЬКО в макете структуры, где структура имеет строку в стиле C (char []) в качестве члена.
Если это не сработает, вам придется использовать :pointer и преобразовать его обратно в строку.Это плохо документировано, но у MemoryPointer есть куча доступных функций, такой как write_string
, это должно помочь.
Другие советы
Итак, благодаря ответу Песто (принятому) я нашел решение.write_string возвращается раньше, если в буфере есть нулевой байт (следует семантике c-строки).Вот код для всех, кто может столкнуться с этой проблемой в будущем.
# Open my application key file and store it in a byte array
appkeyfile = File.read("spotify_appkey.key")
# get the number of bytes in the key
bytecount = appkeyfile.unpack("C*").size
# create a pointer to memory and write the file to it
appkeypointer = FFI::MemoryPointer.new(:char, bytecount)
appkeypointer.put_bytes(0, appkeyfile, 0, bytecount)