T

Win32APIのメモ

dllが用意されているWindows XP embeded入りのハードウェアでFelicaリーダを開発することになり、面白そうなのでRubyで実装してみた。

Win32API経由でdllを叩く際に、渡したポインタに値を入れてもらう関数を実行するやり方がいまいちドキュメントを読んでも不明だったのでメモしておく。

例えば、my_dll.dllというのが用意されていて、初期化関数(void型)とポーリング用関数(INT型、渡したポインタにFelicaのIDmとPMmが入る * どっちも8BYTE)が呼ばれるケース。メモだし例なのでエラー処理は豪快に飛ばす。

require 'Win32API'

# void型の実行
felica = Win32API.new('my_dll', 'felicainit', %w(nil), 'V')
felica.call(0)

ptr_idm = [" " * 256].pack('A8')
ptr_pmm = [" " * 256].pack('A8')

# ポーリング開始
loop dp
  # ポーリング用関数はカードを認識したら0を返す
  polling = Win32API.new('my_dll', 'felicapolling', %(P P), 'i')
  status = polling.call(ptr_idm, ptr_pmm)
  if status == 0
    idm = ptr_idm.unpack('H*')[0]
    pmm = ptr_pmm.unpack(H*)[0]
    # 取得したカード情報を使って素敵なサムシング
  end
end

わからなかったのはポインタの受け渡し方法だったのだけれど、まず引数として2つのポインタを渡すのを明示するには

polling = Win32API.new('my_dll', 'felicapolling', %(P P), 'i')

こんな感じに書ける。「P」はポインタですよという意味で、配列で2つで十分ですよと伝えておく。それから実行時には pack で変数を初期化して

ptr_idm = [" " * 256].pack('A8')
ptr_pmm = [" " * 256].pack('A8')

用意ができたら

status = polling.call(ptr_idm, ptr_pmm)

2つ渡してあげる。ポインタに入った値はエンディアンに気をつけて

idm = ptr_idm.unpack('H*')[0]

こんな感じにunpackしてあげる。以上。

Posted by on 11月 23, 2010 in Ruby

コメントを残す