Вызов C-кода из Ruby - Как использовать возвращаемый указатель?

Проблема:

Я хотел бы использовать в моей программе Ruby алгоритм, который написан на C и предоставляется через DLL.

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

Ruby (1.8.7 и 1.9.3) имеет Win32API модуль, который, кажется, предназначен для того, чтобы довольно легко взаимодействовать с динамическими библиотеками, чтобы делать именно то, что мне нужно

Но проблема в том, что я не могу получить вызов Win32API, чтобы отправить обратно строку.

Подробности:

Сторонняя функция C CodeGen(), Он принимает 6 параметров, в том числе исходную строку, произвольную строку в качестве ключа шифрования, и, для простоты, 4 числовых параметра, один со знаком int, один без знака long и два беззнаковых шорта. Исходя из этого, CodeGen() реализует алгоритм черного ящика для возврата результирующей строки.

Прототип C для CodeGen ():

const char *CodeGen(  int encryp_level, 
                     const char *source_str, const char *encryp_key,
                     unsigned long param_a, 
                     unsigned short param_b, unsigned short param_c
                  )

Обратите внимание, что обе входные строки являются константами, то есть они передаются в CodeGen () в виде строк - так что указатели на константные строки

Возвращаемое значение для CodeGen () также является строкой фиксированной максимальной длины, поэтому он будет возвращать указатель.

Мой вопрос:

Как мне настроить вызов CodeGen () и вернуть строку, которую он должен сгенерировать?

Мои попытки:

Код ниже просто дает мне целые числа в качестве возвращаемого значения, когда я ожидаю получить строку.

require 'Win32API'

codeGen = Win32API.new("encrypt.dll", "CodeGen", "ISSIII", "S")

ret_str = codeGen.Call(3, "foo", "bar", 0, 0, 0)

puts ret_str

Однако вместо возврата строки я получаю целое число. Редактировать: это может быть указатель?

Хотя я использую Ruby 1.9.3 в Windows 7, 64-разрядная версия, я также протестировал вышеупомянутое в Windows XP, 32-разрядной и Ruby 1.8.7, так что я уверен, что это что-то делать с моим использованием самого Win32API.

Не уверен, что проблема в любом из них:

  • целые числа (3, 0, ...) должны быть упакованы?
  • мне нужно различать короткие и длинные типы?
  • я неправильно обрабатываю возвращаемое значение?
  • если возвращаемое значение является указателем, как я могу использовать это в Ruby?
  • что-то другое?

Любое понимание будет высоко ценится!

1 ответ

Решение

Хотя я не знаю, почему Win32API подход не сработал, я нашел более простое решение, используя FFI к проблеме вызова функций C изнутри Ruby или взаимодействия с DLL.


Решение с использованиемFFI

использование FFI в Ruby для взаимодействия с DLL, следующим образом:

  • (1) Установить ffi (работает с ruby ​​1.9.3, ymmv с предыдущими версиями)

    gem install ffi

  • (2) Создайте свой собственный модуль Ruby, чтобы обернуть функцию C

require 'ffi'

module CodeGen                   # Ruby wrapper  (your choice)
  extend FFI::Library
  ffi_lib 'codegen'              # DLL name  (given)
  attach_function 
        :create_code,            # method name  (your choice)
        :CreateCodeShort3,       # DLL function name (given)
          [ :int, :string, :string, :uint, :ushort, :ushort], :string  
                          # specify C param / return value types 
end

ret_str = CodeGen.create_code(3, "foo", "bar", 0,0,0)

puts ret_str
  • (3) Беги. Результат дает строку по желанию.

Готово!

Другие вопросы по тегам