-
Notifications
You must be signed in to change notification settings - Fork 0
Pointers
Traditionally with pointers you’ll have a method, like attach_function :GetForeGroundWindow, [ ], :pointer
What this returns to you is a pointer that, probably, some other library is managing. You don’t need to release this pointer or anything.
To create your own pointer, do something like ptr = MemoryPointer.new(4) # 4 bytes worth of memory
It will be freed when it is GC’ed or you call free.
ptr.address
is the address it points at.
To copy some other pointer, it’s another_ptr = ptr
A pointer is merely a Fixnum that holds a native memory address, so there is no need to do anything special to “copy” a pointer – just assign it to a like you would any other Fixnum. Think of “Pointer” as “fixnum with methods to read/write the native memory at the address”.
Some situations will require allocating native memory and handing off that buffer to an external library. The external library then handles the lifecycle of that buffer including eventually freeing it.
Wrap libc and use its malloc and free functions to allocate and free native memory.
module LibC
extend FFI::Library
ffi_lib FFI::Library::LIBC
# memory allocators
attach_function :malloc, [:size_t], :pointer
attach_function :calloc, [:size_t], :pointer
attach_function :valloc, [:size_t], :pointer
attach_function :realloc, [:pointer, :size_t], :pointer
attach_function :free, [:pointer], :void
# memory movers
attach_function :memcpy, [:pointer, :pointer, :size_t], :pointer
attach_function :bcopy, [:pointer, :pointer, :size_t], :void
end # module LibC
In the ruby code, calls to these functions will return FFI::Pointers. Use the methods defined on FFI::Pointer to move data from ruby memory to native memory.
foo = "a ruby string"
bar = 3.14159
baz = [1, 2, 3, 4, 5]
buffer1 = LibC.malloc foo.size
buffer1.write_string foo
buffer2 = LibC.malloc bar.size
buffer2.write_float bar
# all of the array elements need to be the same type
# meaning you can't mix ints, floats, strings, etc.
buffer3 = LibC.malloc(baz.first.size * baz.size)
buffer3.write_array_of_int baz
The FFI::MemoryPointer
class allocates native memory with automatic garbage collection as a sweetener. When a MemoryPointer goes out of scope, the memory is freed up as part of the garbage collection process.
The MemoryPointer constructor takes 3 arguments: size
, count
and clear
. The size
argument is a symbol type that determines the number of bytes to allocate. The size
argument can also be any object that responds to size
in which case it will allocate that specific number of bytes. The count
argument is a multiplier for size; it will allocate size * count
bytes of memory. Lastly, the clear
argument tells the memory allocator to zero/initialize the memory when true, skip initialization when false.
The block form of MemoryPointer is also useful for automatically freeing the pointer when finished.
FFI::MemoryPointer.new(:int, baz.size) do |p|
p.write_array_of_int(baz)
C.DoSomethingWithArrayOfInt(p)
end
a pointer into a ruby string:
FFI::MemoryPointer.from_string('some string')
How to manage out parameter?
See: Example