-
Notifications
You must be signed in to change notification settings - Fork 0
Basic Usage
Ruby programs can now easily call native C library functions via the FFI mechanism.
The require 'ffi'
directive will load and initialize the FFI library. You then need to use extend FFI::Library
in a module you wish to attach native functions to, and finally, use attach_function
to link the native C functions into the module.
require 'ffi'
module Hello
extend FFI::Library
ffi_lib FFI::Library::LIBC
attach_function 'puts', [ :string ], :int
end
Hello.puts("Hello, World")
The interesting part above is the attach_function
call. It requests that a C function named puts
which takes a :string argument and returns an :int, be attached to the Hello module.
The attach_function
method locates the C function in a specific external library, or any library used by the current process (i.e. libc in the example). To use it, you need to supply the name of the function to load, the parameter types the function takes, and the return type of the function.
Note that windows users will want to add an extra ffi_lib 'msvcrt'
in there, to get access to the puts method.
require 'ffi'
module HelloWin
extend FFI::Library
ffi_lib 'user32'
ffi_convention :stdcall
attach_function :message_box, :MessageBoxA,[ :pointer, :string, :string, :uint ], :int
end
rc = HelloWin.message_box nil, 'Hello Windows!', 'FFI on Windows', 1
puts "Return code: #{rc}"
Using the Windows API is almost as easy as the previous example. Typically you need to tell FFI what Windows library to search via the ffi_lib
method and tell FFI to use the [stdcall](http://en.wikipedia.org/wiki/Stdcall calling) convention used by the Windows API. The ffi_convention
method tells FFI what calling convention to use.
You also need to ensure that you attach the correctly named function to your Ruby module. For all functions that take string arguments, the Windows API provides "short name" macros that expand to function names with a suffix indicating ASCII or Unicode. ANSI versions are suffixed with a "A", and Unicode versions are suffixed with a "W".
Here below there is a partial list of the types supported by FFI. For a more exhaustive list you may look at Types page.
-
:char
and:uchar
- 8 bit signed and unsigned values -
:short
and:ushort
- 16 bit signed and unsigned values -
:int
and:uint
- 32 bit signed and unsigned values -
:long_long
and:ulong_long
- 64 bit signed and unsigned values -
:long
and:ulong
- native cpu word (32 bit or 64bit) signed and unsigned values. Equivalent to C 'long' type. -
:float
and:double
-
:string
- C string, NULL terminated. -
:pointer
- a C pointer
Assuming you have a C library that looks like this, where the function takes a struct as an argument without a pointer:
typedef struct _WHAT {
int d;
} WHAT;
int doit(WHAT w) {
printf("%d\n", w.d);
return w.d;
}
```
The resulting FFI wrapper code for the function should look like this:
```ruby
class WHAT < FFI::Struct
layout :d, :int
end
attach_function 'doit', [WHAT.by_value], :int
```
[StackOverflow Question Relating to this](http://stackoverflow.com/questions/8982393/how-to-wrap-function-in-ruby-ffi-method-that-takes-struct-as-argument/8990201#8990201)
## External links
[Charles Nutter's FFI announcement](http://blog.headius.com/2008/10/ffi-for-ruby-now-available.html)