FlashのJSFL拡張DLLを書いたのでメモ

誰か Flash IDE 用のファイルコピー DLL を C で書いて〜w

というわけで、前々から気になってたC言語による拡張を書いてみました。割と簡単にできたので、手順をまとめておきます。環境はVisual Studio 2005で。
まず、右も左も分からない状態なので、サンプルダウンロードしてきます。zip解凍すると、中にVC8用のプロジェクトがあるので、とりあえず開いてみます。プロジェクトに関係ないヘッダが入ってますが、明らかにVC8のDLLプロジェクトのテンプレそのままですね。

拡張が記述されているのはC言語のソースファイル1つだけです。すごくシンプル。サンプルのcomputeSum関数をざっと眺めると分かりますが、

JSBool computeSum(JSContext *cx, JSObject *obj, unsigned int argc, jsval *argv, jsval *rval)
{
    // ...
}

という形で1つの命令が記述されています。流れとしては以下のとおりです。

  1. 引数の数のチェック
  2. 引数をJSオブジェクトからC言語の型に変換
  3. ごにょごにょ
  4. 結果をC言語の型からJSオブジェクトに変換して戻り値へ代入

命令を増やしたりするときは、下のほうのMM_Init内にJS_DefineFunctionを書き足します。

JS_DefineFunction(_T("hoge"), hoge, 2);

JSから渡される引数や、逆にJSへの戻り値をC言語で扱うために、JS_ValueToTypenameやJS_TypenameToValueという関数(マクロ)が用意されています。これらについてはリファレンスを参照してください。どれもすごくシンプルです。

ちなみに、ここで強調しておきますが、言語はC言語です。クラスはおろか、関数途中での変数宣言や、関数のオーバーロードもありません。この中でもっともネックなのはクラスが無い、つまりデストラクタがないことでしょう。文字列などでメモリを動的に確保する必要がある場合はリークに注意。変数が途中で宣言できないと、関数内の変数の数を減らしたくて関数が短くなるので、コーディング自体はきれいになる傾向があるなと感じました。

で、書いたのがこのTrueFLfile.c。TEXTマクロなどを使ってマルチバイト、Unicode両対応にするつもりだったんですが、よく考えたらマルチバイト文字を扱うことはありえないので意味無かったです。プロジェクト自体はTrueFLfileという形になっています。自分ではFlashを持っていないので動作確認できなかったのですが、何度かのやり取りの後に無事動作するという報告を受けました。以下、引っかかった点とか。

  • JS_ValueToStringで得られる文字コードUnicodeです。マクロ中にchar*という記述があって警告が出ますが、無視で。
  • 渡されてくるURIの文字列がURLエンコードされていました。JS_ExecuteScriptを使ってJSのdecodeURI()を呼び出し、デコードしてます。何かと面倒ですが、このように関数化しておけばなんとかなります。
  • URI中のパイプをコロンに、スラッシュを円マークに置換しないといけない。
  • 定義した関数の戻り値であるJSBoolは、あくまでそのメソッドが成功したかどうかであって、JS自体の戻り値とは関係ありません。引数の*rvalに戻り値を格納してください。何もしなければundefinedが返ります。

拡張の作り方については以上。実際にこれを書くまで勘違いしてたんですが、このC言語拡張ってあくまでFlashIDEを拡張するものであって、生成されるswfから呼び出せるわけではなかったんですね。名前だけちらちらと聞いているGAINERは、こういう拡張機能を使ってswfから外部機器にアクセスしてるもんだと思ってたんですが、全然違ったようです。GAINERはソケット使って通信してるみたいですね。確かに外部アプリケーションと連携させたいのであれば、そういう解決方法をとるのもいいかなと思いました。