Руби Нуби:Как установить строковое значение в структуре FFI

StackOverflow https://stackoverflow.com/questions/745127

  •  09-09-2019
  •  | 
  •  

Вопрос

У меня возникли некоторые проблемы с настройкой структуры 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)
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top