スキップしてメイン コンテンツに移動

js-ctypes実装に見るlibffiの利用(& Windows-MSVCでのビルド法)

Firefox 3.6から入った、chrome権限のJavaScriptから外部バイナリコンポーネントのネイティブ関数を呼び出す機構であるjs-ctypesの実装が、libffiに基づいているということだったので、昔見たときはlibffiはVisual C++はサポートしてなかった記憶があったがFirefoxでビルドできるんだったら単体でもいけるよねーということでjs-ctypesのソースを追いつつ試してみた。

結果から先に述べると、若干手間を要するものの問題なくビルドでき、closureも利用できた。ここでいうclosureとは、呼び出された際にユーザー指定コールバック関数(元の呼び出しに使われたlibffiフォーマットの引数データが渡ってくる)を起動してくれる関数コードを、ユーザーが動的に指定したシグニチャで、ランタイムに実行可能メモリ上に構築してくれるlibffiのAPIが用意されているので、それを利用して作成したバイナリコードを指す。

js-ctypes実装の構造は至極直截的で、JSのオブジェクトとネイティブオブジェクトのバインダとしてのCTypesクラスと、dll/so/dylibみたいなバイナリコンポーネントのラッパーのLibraryクラスから成っている。Library::Declareでシンボルからバイナリ内の関数アドレスを得るときは、PR_FindFunctionSymbolを呼ぶ。これはNSPRの関数で、Windows上では、なんのことはないGetProcAddressが呼ばれる。なんでlibffiなんてものが必要かというと、荒っぽく言ってしまえば、Cでは関数ポインタを宣言しておけばコンパイラが良きに計らってくれるところ、動的言語で同じことをランタイムに行うために、その辺の呼び出し規約上のお膳立てをlibffiが整えてくれるというわけだ。

上述のclosureは、js-ctypesでは、ネイティブコード側にJavascriptの関数をコールバックとして渡す時に利用されている。Javascript関数オブジェクトに関連づけたclosureを作成し、それが呼び出された場合にはCClosure::ClosureStubが呼び出され、関連づけられていたJavascript関数オブジェクトが実行されるようになっている。closureは、コールバック用のプロキシとして働いており、この利用法自体は、libffiの実装内でffi_prep_closure_locの実体がFFI_INIT_TRAMPOLINE呼び出しで、closure用のメモリ領域が「トランポリン」と呼ばれていることからわかるように、想定の範囲内と言える。

Windowsアプリのメッセージハンドラ=ウィンドウプロシージャとしておなじみのWindowProcコールバックは、js-ctypesでは以下のように表現される。

var WNDPROC = ctypes.FunctionType(ctypes.stdcall_abi, ctypes.int, [ctypes.voidptr_t, ctypes.int32_t, ctypes.int32_t, ctypes.int32_t]).ptr;


Windows APIの呼び出し規約はWINAPI(__stdcall)なのでstdcall_abiが指定されている。これを元にしてlibffiがclosureを作成し、closureが起動されるとjs-ctypesが再度Javascriptの関数に戻して実行してやる。これが何を意味するかというと、js-ctypesがあればJavascriptでWindowsアプリのイベント駆動モデルすらも代替できる、つまりMFCとかイラネーよなということになる。これだけ強力なら、Firefox 4のGecko 2がfrozenインターフェイスを破棄してjs-ctypesを媒介にXPCOMを脱構築するという流れも必然であると納得できる。

Windows上でのVisual Studio 2010(VC10)を使ったlibffiのビルド手順としては、以下になる:

  1. Cygwinをインストール。デフォルトのパッケージに加え、Develのmakeが必要なので含めておく。(msysはcygpathが無いので駄目)

  2. Gitをインストール。改行コードの扱いは、チェックアウト=as-is、チェックイン=LFで。cygwinのshは、configureやconfig.sub等のスクリプトが改行コードLFでないと処理できないため。

  3. GitでlibffiのGitHubレポジトリからソース取得。

  4. Visual StudioのVisual Studio Toolsからコマンドプロンプトを起動。Cygwinのフォルダに移動し、Cygwin.batを起動。bash内で/cygdrive/の中のlibffiのソースが置いてあるディレクトリへ移動。

  5. configureオプションについては、libffiのREADME内に簡単な指示はあるものの、Firefoxでのjs-ctypes用configure.inを参考にすべきだろう。
    # Build jsctypes if it's enabled.
    if test "$JS_HAS_CTYPES"; then
      # Run the libffi 'configure' script.
      ac_configure_args="--disable-shared --enable-static --disable-raw-api"
      if test "$MOZ_DEBUG"; then
        ac_configure_args="$ac_configure_args --enable-debug"
      fi
      if test "$DSO_PIC_CFLAGS"; then
        ac_configure_args="$ac_configure_args --with-pic"
      fi
      if test "$CROSS_COMPILE"; then
        case "$target" in
        *-mingw*)
          ac_configure_args="$ac_configure_args --build=$build --host=${target_cpu}-${target_os} HOST_CC=\"$HOST_CC\" CC=\"$CC\""
          ;;
        *-android*)
          CFLAGS="$ANDROID_CFLAGS"
          CPPFLAGS="$ANDROID_CPPFLAGS"
          LDFLAGS="$ANDROID_LDFLAGS"
    
          export AS CC CXX CPP LD AR RANLIB STRIP CPPFLAGS CFLAGS LDFLAGS
    
          ac_configure_args="$ac_configure_args --build=$build --host=${target_cpu}-${target_os} HOST_CC=\"$HOST_CC\""
          ;;
        *)
          ac_configure_args="$ac_configure_args --build=$build --host=$target HOST_CC=\"$HOST_CC\" CC=\"$CC\""
          ;;
        esac
      fi
      if test "$_MSC_VER"; then
        # Use a wrapper script for cl and ml that looks more like gcc.
        # autotools can't quite handle an MSVC build environment yet.
        ac_configure_args="$ac_configure_args LD=link CPP=\"cl -nologo -EP\" SHELL=sh.exe"
        case "${target_cpu}" in
        x86_64)
          # Need target since MSYS tools into mozilla-build may be 32bit
          ac_configure_args="$ac_configure_args CC=\"$_topsrcdir/ctypes/libffi/msvcc.sh -m64\" --build=$build --host=$target"
          ;;
        *)
          ac_configure_args="$ac_configure_args CC=$_topsrcdir/ctypes/libffi/msvcc.sh"
          ;;
        esac
      fi
      if test "$SOLARIS_SUNPRO_CC"; then
        # Always use gcc for libffi on Solaris
        if test ! "$HAVE_64BIT_OS"; then
          ac_configure_args="$ac_configure_args CC=gcc CFLAGS=-m32"
        else
          ac_configure_args="$ac_configure_args CC=gcc CFLAGS=-m64"
        fi
      fi
      if test "$OS_ARCH" = "OS2"; then
        ac_configure_args="$ac_configure_args CFLAGS=-Zomf AR=emxomfar"
      fi
      if test -n "$MOZ_THUMB2"; then
        ac_configure_args="$ac_configure_args --enable-thumb2"
      fi
    
      # Use a separate cache file for libffi, since it does things differently
      # from our configure.
      mkdir -p $_objdir/ctypes/libffi
      old_cache_file=$cache_file
      cache_file=$_objdir/ctypes/libffi/config.cache
      old_config_files=$CONFIG_FILES
      unset CONFIG_FILES
      AC_OUTPUT_SUBDIRS(ctypes/libffi)
      cache_file=$old_cache_file
      ac_configure_args="$_SUBDIR_CONFIG_ARGS"
      CONFIG_FILES=$old_config_files
    fi


    リリース版は
    ./configure --disable-shared --enable-static CC=./msvcc.sh LD=link CPP="cl -nologo -EP"
    デバッグ版は
    ./configure --disable-shared --enable-static --enable-debug CC=./msvcc.sh LD=link CPP="cl -nologo -EP"

  6. ここでmakeしようとすると以下のエラーに遭遇する:
    makelibtool: compile: ./msvcc.sh -DHAVE_CONFIG_H -I. -I. -I./include -Iinclude -I./
    src -Wall -g -fexceptions -O2 -c src\\debug.c -DDLL_EXPORT -DPIC
    cl -MD -nologo -W3 -DHAVE_CONFIG_H -I. -I. -I./include -Iinclude -I./src -Zi -DE
    BUG -O2 -OPT:REF -OPT:ICF -INCREMENTAL:NO -c src\debug.c -DDLL_EXPORT -DPIC
    cl : コマンド ライン warning D9002 : 不明なオプション '-OP' を無視します
    cl : コマンド ライン warning D9002 : 不明なオプション '-OT' を無視します
    cl : コマンド ライン warning D9002 : 不明なオプション '-O:' を無視します
    cl : コマンド ライン warning D9002 : 不明なオプション '-OR' を無視します
    cl : コマンド ライン warning D9002 : 不明なオプション '-OE' を無視します
    cl : コマンド ライン warning D9002 : 不明なオプション '-OF' を無視します
    cl : コマンド ライン warning D9002 : 不明なオプション '-OP' を無視します
    cl : コマンド ライン warning D9002 : 不明なオプション '-OT' を無視します
    cl : コマンド ライン warning D9002 : 不明なオプション '-O:' を無視します
    cl : コマンド ライン warning D9002 : 不明なオプション '-OI' を無視します
    cl : コマンド ライン warning D9002 : 不明なオプション '-OC' を無視します
    cl : コマンド ライン warning D9002 : 不明なオプション '-OF' を無視します
    srcdebug.c
    c1 : fatal error C1083: ソース ファイルを開けません。'srcdebug.c': No such file or directory
    どうやらsrc\debug.cのバックスラッシュがおかしいというのがわかるので、libtool内の

    # Fix the shell variable $srcfile for the compiler.
    fix_srcfile_path="\`cygpath -w \"\$srcfile\"\`"


    の-wを-uに変更

  7. ここでmakeしようとすると今度は以下のエラーに遭遇する:
    E:\program\src\libffi\libffi-github\include\ffitarget.h : warning C4819: ファイ
    ルは、現在のコード ページ (932) で表示できない文字を含んでいます。データの損失を
    防ぐために、ファイルを Unicode 形式で保存してください。
    E:\program\src\libffi\libffi-github\include\ffitarget.h(1) : error C2059: 構文エ
    ラー : '!'
    c:\program files (x86)\microsoft visual studio 10.0\vc\include\codeanalysis\sour
    ceannotations.h(91) : error C2061: 構文エラー : 識別子 'size_t'
    c:\program files (x86)\microsoft visual studio 10.0\vc\include\codeanalysis\sour
    ceannotations.h(92) : error C2061: 構文エラー : 識別子 'ValidBytesConst'
    c:\program files (x86)\microsoft visual studio 10.0\vc\include\codeanalysis\sour
    ceannotations.h(92) : error C2059: 構文エラー : ';'
    c:\program files (x86)\microsoft visual studio 10.0\vc\include\codeanalysis\sour
    ceannotations.h(97) : error C2061: 構文エラー : 識別子 'WritableElementsConst'
    c:\program files (x86)\microsoft visual studio 10.0\vc\include\codeanalysis\sour
    ceannotations.h(97) : error C2059: 構文エラー : ';'
    c:\program files (x86)\microsoft visual studio 10.0\vc\include\codeanalysis\sour
    ceannotations.h(98) : error C2061: 構文エラー : 識別子 'WritableBytesConst'
    c:\program files (x86)\microsoft visual studio 10.0\vc\include\codeanalysis\sour
    ceannotations.h(98) : error C2059: 構文エラー : ';'
    c:\program files (x86)\microsoft visual studio 10.0\vc\include\codeanalysis\sour
    ceannotations.h(103) : error C2061: 構文エラー : 識別子 'ElementSizeConst'
    c:\program files (x86)\microsoft visual studio 10.0\vc\include\codeanalysis\sour
    ceannotations.h(103) : error C2059: 構文エラー : ';'
    c:\program files (x86)\microsoft visual studio 10.0\vc\include\codeanalysis\sour
    ceannotations.h(107) : error C2059: 構文エラー : '}'
    c:\program files (x86)\microsoft visual studio 10.0\vc\include\codeanalysis\sour
    ceannotations.h(122) : error C2061: 構文エラー : 識別子 'size_t'
    c:\program files (x86)\microsoft visual studio 10.0\vc\include\codeanalysis\sour
    ceannotations.h(123) : error C2061: 構文エラー : 識別子 'ValidBytesConst'
    c:\program files (x86)\microsoft visual studio 10.0\vc\include\codeanalysis\sour
    ceannotations.h(123) : error C2059: 構文エラー : ';'
    c:\program files (x86)\microsoft visual studio 10.0\vc\include\codeanalysis\sour
    ceannotations.h(128) : error C2061: 構文エラー : 識別子 'WritableElementsConst'
    c:\program files (x86)\microsoft visual studio 10.0\vc\include\codeanalysis\sour
    ceannotations.h(128) : error C2059: 構文エラー : ';'
    c:\program files (x86)\microsoft visual studio 10.0\vc\include\codeanalysis\sour
    ceannotations.h(129) : error C2061: 構文エラー : 識別子 'WritableBytesConst'
    c:\program files (x86)\microsoft visual studio 10.0\vc\include\codeanalysis\sour
    ceannotations.h(129) : error C2059: 構文エラー : ';'
    c:\program files (x86)\microsoft visual studio 10.0\vc\include\codeanalysis\sour
    ceannotations.h(134) : error C2061: 構文エラー : 識別子 'ElementSizeConst'
    c:\program files (x86)\microsoft visual studio 10.0\vc\include\codeanalysis\sour
    ceannotations.h(134) : error C2059: 構文エラー : ';'
    c:\program files (x86)\microsoft visual studio 10.0\vc\include\codeanalysis\sour
    ceannotations.h(139) : error C2059: 構文エラー : '}'
    C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\INCLUDE\crtdefs.h(409) :
    error C2061: 構文エラー : 識別子 'rsize_t'
    C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\INCLUDE\crtdefs.h(409) :
    error C2059: 構文エラー : ';'
    E:\program\src\libffi\libffi-github\include\ffi.h(97) : error C2016: C では、構
    造体または共用体に少なくとも 1 つのメンバーが必要です。
    E:\program\src\libffi\libffi-github\include\ffi.h(97) : error C2061: 構文エラー
    : 識別子 'size_t'
    E:\program\src\libffi\libffi-github\include\ffi.h(101) : error C2059: 構文エラー
    : '}'
    E:\program\src\libffi\libffi-github\include\ffi.h(153) : error C2061: 構文エラー
    : 識別子 'ffi_type_void'
    E:\program\src\libffi\libffi-github\include\ffi.h(153) : error C2059: 構文エラー
    : ';'
    E:\program\src\libffi\libffi-github\include\ffi.h(154) : error C2061: 構文エラー
    : 識別子 'ffi_type_uint8'
    E:\program\src\libffi\libffi-github\include\ffi.h(154) : error C2059: 構文エラー
    : ';'
    E:\program\src\libffi\libffi-github\include\ffi.h(155) : error C2061: 構文エラー
    : 識別子 'ffi_type_sint8'
    E:\program\src\libffi\libffi-github\include\ffi.h(155) : error C2059: 構文エラー
    : ';'
    E:\program\src\libffi\libffi-github\include\ffi.h(156) : error C2061: 構文エラー
    : 識別子 'ffi_type_uint16'
    E:\program\src\libffi\libffi-github\include\ffi.h(156) : error C2059: 構文エラー
    : ';'
    E:\program\src\libffi\libffi-github\include\ffi.h(157) : error C2061: 構文エラー
    : 識別子 'ffi_type_sint16'
    E:\program\src\libffi\libffi-github\include\ffi.h(157) : error C2059: 構文エラー
    : ';'
    E:\program\src\libffi\libffi-github\include\ffi.h(158) : error C2061: 構文エラー
    : 識別子 'ffi_type_uint32'
    E:\program\src\libffi\libffi-github\include\ffi.h(158) : error C2059: 構文エラー
    : ';'
    E:\program\src\libffi\libffi-github\include\ffi.h(159) : error C2061: 構文エラー
    : 識別子 'ffi_type_sint32'
    E:\program\src\libffi\libffi-github\include\ffi.h(159) : error C2059: 構文エラー
    : ';'
    E:\program\src\libffi\libffi-github\include\ffi.h(160) : error C2061: 構文エラー
    : 識別子 'ffi_type_uint64'
    E:\program\src\libffi\libffi-github\include\ffi.h(160) : error C2059: 構文エラー
    : ';'
    E:\program\src\libffi\libffi-github\include\ffi.h(161) : error C2061: 構文エラー
    : 識別子 'ffi_type_sint64'
    E:\program\src\libffi\libffi-github\include\ffi.h(161) : error C2059: 構文エラー
    : ';'
    E:\program\src\libffi\libffi-github\include\ffi.h(162) : error C2061: 構文エラー
    : 識別子 'ffi_type_float'
    E:\program\src\libffi\libffi-github\include\ffi.h(162) : error C2059: 構文エラー
    : ';'
    E:\program\src\libffi\libffi-github\include\ffi.h(163) : error C2061: 構文エラー
    : 識別子 'ffi_type_double'
    E:\program\src\libffi\libffi-github\include\ffi.h(163) : error C2059: 構文エラー
    : ';'
    E:\program\src\libffi\libffi-github\include\ffi.h(164) : error C2061: 構文エラー
    : 識別子 'ffi_type_pointer'
    E:\program\src\libffi\libffi-github\include\ffi.h(164) : error C2059: 構文エラー
    : ';'
    E:\program\src\libffi\libffi-github\include\ffi.h(182) : error C2016: C では、構
    造体または共用体に少なくとも 1 つのメンバーが必要です。
    E:\program\src\libffi\libffi-github\include\ffi.h(182) : error C2061: 構文エラー
    : 識別子 'ffi_abi'
    E:\program\src\libffi\libffi-github\include\ffi.h(184) : error C2143: 構文エラー
    : '{' が '*' の前にありません。
    E:\program\src\libffi\libffi-github\include\ffi.h(185) : error C2143: 構文エラー
    : '{' が '*' の前にありません。
    E:\program\src\libffi\libffi-github\include\ffi.h(191) : error C2059: 構文エラー
    : '}'
    E:\program\src\libffi\libffi-github\include\ffi.h(208) : error C2016: C では、構
    造体または共用体に少なくとも 1 つのメンバーが必要です。
    E:\program\src\libffi\libffi-github\include\ffi.h(208) : error C2061: 構文エラー
    : 識別子 'ffi_sarg'
    E:\program\src\libffi\libffi-github\include\ffi.h(209) : error C2061: 構文エラー
    : 識別子 'uint'
    E:\program\src\libffi\libffi-github\include\ffi.h(209) : error C2059: 構文エラー
    : ';'
    E:\program\src\libffi\libffi-github\include\ffi.h(213) : error C2059: 構文エラー
    : '}'
    E:\program\src\libffi\libffi-github\include\ffi.h(226) : error C2061: 構文エラー
    : 識別子 'ffi_java_raw'
    E:\program\src\libffi\libffi-github\include\ffi.h(226) : error C2059: 構文エラー
    : ';'
    E:\program\src\libffi\libffi-github\include\ffi.h(230) : error C2143: 構文エラー
    : ')' が '*' の前にありません。
    E:\program\src\libffi\libffi-github\include\ffi.h(230) : error C2143: 構文エラー
    : '{' が '*' の前にありません。
    E:\program\src\libffi\libffi-github\include\ffi.h(231) : error C2059: 構文エラー
    : '型'
    E:\program\src\libffi\libffi-github\include\ffi.h(235) : error C2143: 構文エラー
    : ')' が '*' の前にありません。
    E:\program\src\libffi\libffi-github\include\ffi.h(235) : error C2143: 構文エラー
    : '{' が '*' の前にありません。
    E:\program\src\libffi\libffi-github\include\ffi.h(235) : error C2059: 構文エラー
    : '型'
    E:\program\src\libffi\libffi-github\include\ffi.h(235) : error C2059: 構文エラー
    : ')'
    E:\program\src\libffi\libffi-github\include\ffi.h(236) : error C2143: 構文エラー
    : ')' が '*' の前にありません。
    E:\program\src\libffi\libffi-github\include\ffi.h(236) : error C2143: 構文エラー
    : '{' が '*' の前にありません。
    E:\program\src\libffi\libffi-github\include\ffi.h(236) : error C2143: 構文エラー
    : ';' が '*' の前にありません。
    E:\program\src\libffi\libffi-github\include\ffi.h(236) : error C2059: 構文エラー
    : '型'
    E:\program\src\libffi\libffi-github\include\ffi.h(236) : error C2059: 構文エラー
    : ')'
    E:\program\src\libffi\libffi-github\include\ffi.h(237) : error C2061: 構文エラー
    : 識別子 'ffi_raw_size'
    E:\program\src\libffi\libffi-github\include\ffi.h(237) : error C2059: 構文エラー
    : ';'
    E:\program\src\libffi\libffi-github\include\ffi.h(237) : error C2143: 構文エラー
    : ')' が '*' の前にありません。
    E:\program\src\libffi\libffi-github\include\ffi.h(237) : error C2143: 構文エラー
    : '{' が '*' の前にありません。
    E:\program\src\libffi\libffi-github\include\ffi.h(237) : error C2059: 構文エラー
    : ')'
    E:\program\src\libffi\libffi-github\include\ffi.h(243) : error C2143: 構文エラー
    : ')' が '*' の前にありません。
    E:\program\src\libffi\libffi-github\include\ffi.h(243) : error C2143: 構文エラー
    : '{' が '*' の前にありません。
    E:\program\src\libffi\libffi-github\include\ffi.h(244) : error C2059: 構文エラー
    : '型'
    E:\program\src\libffi\libffi-github\include\ffi.h(248) : error C2143: 構文エラー
    : ')' が '*' の前にありません。
    E:\program\src\libffi\libffi-github\include\ffi.h(248) : error C2143: 構文エラー
    : '{' が '*' の前にありません。
    E:\program\src\libffi\libffi-github\include\ffi.h(248) : error C2059: 構文エラー
    : '型'
    E:\program\src\libffi\libffi-github\include\ffi.h(248) : error C2059: 構文エラー
    : ')'
    E:\program\src\libffi\libffi-github\include\ffi.h(249) : error C2143: 構文エラー
    : ')' が '*' の前にありません。
    E:\program\src\libffi\libffi-github\include\ffi.h(249) : error C2143: 構文エラー
    : '{' が '*' の前にありません。
    E:\program\src\libffi\libffi-github\include\ffi.h(249) : error C2143: 構文エラー
    : ';' が '*' の前にありません。
    E:\program\src\libffi\libffi-github\include\ffi.h(249) : error C2059: 構文エラー
    : '型'
    E:\program\src\libffi\libffi-github\include\ffi.h(249) : error C2059: 構文エラー
    : ')'
    E:\program\src\libffi\libffi-github\include\ffi.h(250) : error C2061: 構文エラー
    : 識別子 'ffi_java_raw_size'
    E:\program\src\libffi\libffi-github\include\ffi.h(250) : error C2059: 構文エラー
    : ';'
    E:\program\src\libffi\libffi-github\include\ffi.h(250) : error C2143: 構文エラー
    : ')' が '*' の前にありません。
    E:\program\src\libffi\libffi-github\include\ffi.h(250) : error C2143: 構文エラー
    : '{' が '*' の前にありません。
    E:\program\src\libffi\libffi-github\include\ffi.h(250) : error C2059: 構文エラー
    : ')'
    E:\program\src\libffi\libffi-github\include\ffi.h(358) : error C2143: 構文エラー
    : ')' が '*' の前にありません。
    E:\program\src\libffi\libffi-github\include\ffi.h(358) : error C2143: 構文エラー
    : '{' が '*' の前にありません。
    E:\program\src\libffi\libffi-github\include\ffi.h(359) : error C2146: 構文エラー
    : ';' が、識別子 'abi' の前に必要です。
    E:\program\src\libffi\libffi-github\include\ffi.h(360) : error C2059: 構文エラー
    : '型'
    E:\program\src\libffi\libffi-github\include\ffi.h(362) : error C2059: 構文エラー
    : ')'
    E:\program\src\libffi\libffi-github\include\ffi.h(362) : fatal error C1003: プロ
    グラム内のエラーが 100 個を超えました。コンパイルは中断されます。
    make[2]: *** [src/debug.lo] Error 1
    make[2]: Leaving directory `/cygdrive/e/program/src/libffi/libffi-github'
    make[1]: *** [all-recursive] Error 1
    make[1]: Leaving directory `/cygdrive/e/program/src/libffi/libffi-github'
    make: *** [all] Error 2

    include/ffitarget.hのsymlinkが機能していないことによるエラーなので、src/x86/ffitarget.hをinclude/ffitarget.hに上書きコピーする。

  8. 再度make。.libsにlibffi.libスタティックリンクライブラリができる。

libffiを使うプロジェクトのリンカーインプットにlibffi.libを指定してやればビルドが通る。libffiの利用例は、testsuite内のコードを参照すればよい。

EnumWindows APIからclosureを呼び出すサンプルコードは以下。

#include <windows.h>
#include <stdio.h>
#include <ffi.h>

static void closure_stub(ffi_cif* cif, void* resp, void** args, void* userdata)
{
 ++(*((DWORD*)userdata));

 wchar_t buf[256];
 HWND hwnd = *(HWND*)(args[0]);

 if (::GetWindowTextW(hwnd, buf, 256) != 0 && ::IsWindowVisible(hwnd))
 {
  ::wprintf_s(L"HWND: 0x%08x - %s\r\n", DWORD(hwnd), buf);
 }

 *(BOOL*)resp = TRUE;
}

int _tmain(int argc, _TCHAR* argv[])
{
 ::setlocale(LC_ALL, "Japanese");

 void* code;
 ffi_closure* pcl = (ffi_closure*)ffi_closure_alloc(sizeof(ffi_closure), &code);

 ffi_type* cl_arg_types[2];
 cl_arg_types[0] = &ffi_type_pointer;
 cl_arg_types[1] = &ffi_type_pointer;

 ffi_cif cif;
 _ASSERTE(ffi_prep_cif(&cif, FFI_STDCALL, 2, &ffi_type_uint32, cl_arg_types) == FFI_OK);

 static DWORD dwInvokeCount = 0;

 _ASSERTE(ffi_prep_closure_loc(pcl, &cif, closure_stub, (void*)&dwInvokeCount, code) == FFI_OK);

 _ASSERTE(::EnumWindows((WNDENUMPROC)code, NULL) != 0);

 ::wprintf_s(L"Closure - invoked %d times\r\n", dwInvokeCount);

 ffi_closure_free(pcl);

 return 0;
}

コメント