Firefox 3.7での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);