Firefox 3.7でのjs-ctypes

現在js-ctypesは開発中のため、今後仕様が変わる可能性があります。

去年行われたFirefox Developers Conference 2009でjs-ctypesについて説明しましたが、いくつかの制限があり、Firefox 3.6で使える状況はあまりなかったかと思います。現在開発を行っているFirefox 3.7では、js-ctypesが大幅に改良される予定で、現在のビルドでは、構造体のサポートやコールバック関数のサポートが含まれます。今回は構造体の使用について説明します。

この説明では、Windowsに含まれるカラーピッカー(色の選択をするダイアログ)を表示する例を挙げます。

Windowsでカラーピッカーを表示するAPIは、ChooseColorです。この関数は引数として以下の構造体のポインタを持ちます。

typedef struct {
 DWORD        lStructSize;
 HWND         hwndOwner;
 HWND         hInstance;
 COLORREF     rgbResult;
 COLORREF     *lpCustColors;
 DWORD        Flags;
 LPARAM       lCustData;
 LPCCHOOKPROC lpfnHook;
 LPCTSTR      lpTemplateName;
} CHOOSECOLOR, *LPCHOOSECOLOR;

これをctypes.StructTypeを利用して、js-ctypesで定義します。この例では、使わないメンバはuint32_tにしていますが、lpTemplateNameは文字列のポインタとして定義するのが正しいです。

var custColors_type = ctypes.ArrayType(ctypes.int32_t, 16);
const CHOOSECOLOR = new ctypes.StructType(
 'CHOOSECOLOR',
 [
  {'lStructSize': ctypes.uint32_t},
  {'hwndOwner' : ctypes.uint32_t},
  {'hInstance' : ctypes.uint32_t},
  {'rgbResult' : ctypes.uint32_t},
  {'lpCustColors' : custColors_type.ptr},
  {'Flags' : ctypes.uint32_t},
  {'lCustData' : ctypes.uint32_t},
  {'lpfnHook' : ctypes.uint32_t},
  {'lpTemplateName' : ctypes.uint32_t}
 ]);

構造体の定義が終わったら、関数を定義しましょう。定義方法は変わりませんが、引数でポインタ型を渡しています。

var comdlg32 = ctypes.open("comdlg32");
var ChooseColor = comdlg32.declare("ChooseColorW", ctypes.stdcall_abi, ctypes.int32_t, CHOOSECOLOR.ptr);

関数を呼び出すために、値をセットします。構造体のメンバにポインタを渡す必要があるため、addressを利用します。

var custColors = new custColors_type();
var col = new CHOOSECOLOR (CHOOSECOLOR.size, 0, 0, 0, custColors.address(), 0, 0, 0, 0);

値を作成したので、関数を呼び出しましょう。

ChooseColor(col.address());

そうすると、col.rgbResultにユーザーが選択した色の値がセットされますので、それを参照するとどの色を選択したかがわかります。

alert(col.rgbResult);

このように、構造体を引数に持つ関数の呼び出し方法が追加されています。これでjs-ctypesが利用できる範囲も広くなったと思います。次は、コールバック関数の利用について説明したいと思います。

なお、今回サンプルで作成したすべてのコードは以下になります。

Components.utils.import("resource://gre/modules/ctypes.jsm");

var custColors_type = ctypes.ArrayType(ctypes.int32_t, 16);
const CHOOSECOLOR = new ctypes.StructType(
 'CHOOSECOLOR',
 [
  {'lStructSize': ctypes.uint32_t},
  {'hwndOwner' : ctypes.uint32_t},
  {'hInstance' : ctypes.uint32_t},
  {'rgbResult' : ctypes.uint32_t},
  {'lpCustColors' : custColors_type.ptr},
  {'Flags' : ctypes.uint32_t},
  {'lCustData' : ctypes.uint32_t},
  {'lpfnHook' : ctypes.uint32_t},
  {'lpTemplateName' : ctypes.uint32_t}
 ]);

var comdlg32 = ctypes.open("comdlg32");
var ChooseColor = comdlg32.declare("ChooseColorW", ctypes.stdcall_abi, ctypes.int32_t, CHOOSECOLOR.ptr);

var custColors = new custColors_type();
var col = new CHOOSECOLOR (CHOOSECOLOR.size, 0, 0, 0, custColors.address(), 0, 0, 0, 0);

ChooseColor(col.address());
alert(col.rgbResult);