MLtonでWin32APIを呼び出す


Cygwin上のMLton*1でWin32APIを使用する簡単な例を紹介します。
以下の2つの例では異なる方法で右図のようなメッセージボックスを表示します。
コード全体はgistに置いてあります。

direct call

_import 式でシンボルと型を書くとお手軽に外部関数が使えます。

local
  val MessageBoxA =
        _import "MessageBoxA" stdcall: C_Pointer.t * string * string * Word32.word -> int;
in
  val _ = MessageBoxA (C_Pointer.null, "Hello World!", "MLton Static FFI", 0w4096)
end

indirect call

libdlを使って共有ライブラリから取り出した関数ポインタを呼ぶ方法もあります。
関数ポインタを呼び出す場合、 import式に `*' を指定します。

local
  val double_to_double = _import * : DynLink.fptr -> real -> real;
  val user32 = DynLink.dlopen ("user32.dll", DynLink.RTLD_LAZY)
  val sigMessageBoxA =
    _import * : DynLink.fptr -> C_Pointer.t * string * string * Word32.word -> int;
  val msgbox_ptr = DynLink.dlsym (user32, "MessageBoxA")
  val dynMessageBoxA = sigMessageBoxA msgbox_ptr
in
  val _ = dynMessageBoxA (C_Pointer.null, "Hello World!", "MLton Dynamic FFI", 0w4096)
  val _ = DynLink.dlclose user32
end

ビルド

allowFFI を有効にしてビルドする必要があります。

# cat win32.mlb
ann "allowFFI true" in
	$(SML_LIB)/basis/basis.mlb
	$(SML_LIB)/basis/mlton.mlb
	$(SML_LIB)/basis/c-types.mlb
	dynlink.sml
	win32.sml
end
# mlton win32.mlb

*1:win7(64bit) + mlton{20100608|20130715}で確認