サンプル

最終更新:

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
}
記事メニュー
人気記事ランキング
目安箱バナー