Вызов 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) Беги. Результат дает строку по желанию.
Готово!