用意するもの
- RC-S300などのPASORIリーダーと初期設定
- felicalib.dll
- fsharpの開発環境
felicalib.dllは下記より
早速ですがソースコード
open System.Runtime.InteropServices
open System
(*
felicalib.dllの場所を絶対パスで入れておくとわかりやすいが
まあ相対パスでもちゃんと配置すれば動きます。
open, close, initなどはAPI仕様書に書いてあります。
http://felicalib.tmurakam.org/refdoc/
*)
module InteropWithNative =
[<DllImport(@"felicalib.dll")>]
extern IntPtr pasori_open()
[<DllImport(@"felicalib.dll")>]
extern void pasori_close()
[<DllImport(@"felicalib.dll")>]
extern void pasori_init(IntPtr)
[<DllImport(@"felicalib.dll")>]
extern IntPtr felica_polling(IntPtr, int, int, int)
[<DllImport(@"felicalib.dll")>]
extern void felica_getidm(IntPtr, byte[])
(* pasoriのpointerをopenで取得する *)
let pasoriPointer = InteropWithNative.pasori_open ()
(* pasoriをinitする *)
InteropWithNative.pasori_init (pasoriPointer)
(* felicaのpollingを開始する *)
let felica_polling = InteropWithNative.felica_polling (pasoriPointer, 0xffff, 0, 0)
(* 返り値を入れるbyteArrayを用意する *)
let byteArray = Array.zeroCreate 8
(* byte to string *)
let byteToStr byteArr = BitConverter.ToString(byteArr)
InteropWithNative.felica_getidm (felica_polling, byteArray)
printfn "IDm: %A" (byteToStr byteArray)
(* log.txtファイルに書き出す *)
let log = System.IO.File.AppendText("log.txt")
log.WriteLine(byteToStr byteArray)
log.Close()
fsharpでC++などで作成されたライブラリを使用する際は、InteropServicesを使用します。
あとは自分で型定義を書いてあげて使う感じですね。
最近はcopilotのお陰でC++側のAPI仕様書をコメントアウトで書いておけば勝手に書いてくれます。
注意点として、x86系で作成されたライブラリに対応する場合、fsharpのコンパイルもx86系で通す必要があります。
fsprojの下に<PlatformTarget>x86</PlatformTarget>
などとしておくと良いでしょう。
こんな書き方するなら無理に関数型言語使わなくてもC#とかVBでええやんっていう話なんですが、F#のほうが手続き型であっても書きやすい気がするのです。めちゃくちゃシンプルに書けます。
もしJSで書くならff-napiとか、最近ならkoffiを使用することになると思います。
JSでも同じことができるんですけど、JSはIntPtrみたいなポインタの操作が面倒なのと、返り値などの操作が非常に面倒くさいのと、そもそもx86系のnode.jsを入れておかないとx86のDLLがうまく動きません。そういうハマりがあるので仕方がなくFsharpで頑張ったということでした。普通はVBかC#でいいと思います。サンプルも豊富にあるし。
F#で外部dllを使うソースコードがあんまりなかったのですが、まあ動いたのでOKとしましょう。