サンプル
最終更新:
tmtbnc
-
view
samples
構造体
ffi-0.5.1で確認
- 簡単な例
class XYZ < FFI::Struct layout :x, :int, :y, :int, :z, :int end a = XYZ.new p a[:x] a[:x] = 3 p a[:x]
- 配列メンバ
class TestA < FFI::Struct layout :a, :int, :b, [:int, 3], :c, :int end s = TestA.new p s[:b][2] s[:b][2] = 100 p s[:b][2] s[:c] = 5 p s[:b][3]
- 共用体
class TestUnion < FFI::Union layout :a, :int, :b, :char end n = TestUnion.new p n[:b] n[:a] = 0xff07 p n[:a] p n[:b]
- アラインメント
class TestB < FFI::Struct layout :a, :long_long, :b, :char end p TestB.size p TestB.align
- 文字列
class TestC < FFI::Struct layout :chars, [:char, 16] end tc = TestC.new p tc[:chars].to_ptr.put_string(0, "0123456789") p tc[:chars].to_str p tc[:chars].to_ptr.put_string(0, "ZZZZZ") p tc[:chars].to_str p tc[:chars].to_ptr.put_bytes(0, "1234567890123456") p tc[:chars].to_str
関数
- Win32 APIの例
module WinUser extend FFI::Library ffi_lib 'user32' ffi_convention(:stdcall) MB_OK = 1 attach_function(:message_box, :MessageBoxA, [:long, :string, :string, :int], :int) end p WinUser.message_box(0, "message", "window caption", WinUser::MB_OK)
- だいたいの流れ
p lib = FFI::DynamicLibrary.open("user32", FFI::DynamicLibrary::RTLD_LAZY | FFI::DynamicLibrary::RTLD_GLOBAL) p function = lib.find_function("MessageBoxA") # FFI::Library::Symbol raise FFI::NotFoundError.new(name, lib.name) unless function args = [:long, :string, :string, :int].map {|a| FFI.find_type(a) } ret_type = FFI.find_type(:int) p invoker = FFI::Function.new(ret_type, args, function, {:convention => :stdcall}) raise FFI::NotFoundError.new(name, lib.name) unless invoker p r = invoker.call(0, "message", "window caption", 0)
- コールバックの例。ウィンドウの列挙 (ffi-0.6.3で動作確認。古いバージョンだとダメ)
require 'ffi' class Window extend FFI::Library ffi_lib('user32') ffi_convention(:stdcall) [ [:ulong, :uintptr_t], [:long, :intptr_t], [:uintptr_t, :HWND], [:ulong, :DWORD], [:int, :BOOL], [:intptr_t, :LPARAM], [:pointer, :LPTSTR], ].each {|t| typedef(*t) } callback(:EnumWindowsProc, [:HWND, :LPARAM], :BOOL) attach_function(:EnumWindows, [:EnumWindowsProc, :LPARAM], :BOOL) attach_function(:GetWindowTextA, [:HWND, :LPTSTR, :int], :int) attach_function(:GetClassNameA, [:HWND, :LPTSTR, :int], :int) attach_function(:IsWindowVisible, [:HWND], :BOOL) class << self alias :GetWindowText :GetWindowTextA alias :GetClassName :GetClassNameA end def self.each(lparam=0, &block) EnumWindows(lparam) {|hwnd, lparam| block.call(self.new(hwnd), lparam) } end attr_reader :hwnd def initialize(hwnd) @hwnd = hwnd end def title pstr = FFI::MemoryPointer.new(1,256) self.class.GetWindowText(@hwnd, pstr, pstr.size) pstr.read_string end def class_name pstr = FFI::MemoryPointer.new(1,256) self.class.GetClassName(@hwnd, pstr, pstr.size) pstr.read_string end def visible? self.class.IsWindowVisible(@hwnd).nonzero? end end Window.each {|win, lparam| puts "#{win.title} [#{win.class_name}]" if win.visible? 1 }