TJS2 は C++ 等の言語で書かれたネイティブクラスを扱うための機構を持っています。
各オブジェクト (iTJSDispatch2 インターフェース) にはネイティブインスタンスと呼ばれる、iTJSNativeInstance 型のオブジェクトを登録することができ、これを オブジェクトから取り出すことができます。
ネイティブインスタンスは一意なクラス ID で識別され、ネイティブクラスの作成時にはクラス ID を取得する必要があります。
しかし、これらの操作を行う為のマクロ群が tjsNative.h に定義されているので、これらを利用するのが楽です。
以下の例は、これらのマクロを使って簡単なクラスを実装するものです。
まず、ネイティブインスタンスの実装です。ネイティブインスタンスを実装するには tTJSNativeInstance からクラスを導出します。tTJSNativeInstance は tjsNative.cpp / tjsNative.h に実装されているクラスで、iTJSNativeInstance の基本的な動作を実装しています。
例:
1|class NI_Test : public tTJSNativeInstance
2|{
3|public:
4| NI_Test()
5| {
6|
7| Value = 0;
8| }
9|
10| tjs_error TJS_INTF_METHOD
11| Construct(tjs_int numparams, tTJSVariant **param, iTJSDispatch2 *tjs_obj)
12| {
13|
14|
15|
16| if(numparams >= 1 && param[0]->Type() != tvtVoid)
17| Value = (tjs_int)*param[0];
18|
19| return S_OK;
20| }
21|
22| void TJS_INTF_METHOD Invalidate()
23| {
24|
25| }
26|
27| void SetValue(tjs_int n) { Value = n; }
28| tjs_int GetValue() const { return Value; }
29|
30| tjs_int GetSquare() const { return Value*Value; }
31| void Add(tjs_int n) { Value += n; }
32| void Print() const { printf("%d\n", Value); }
33|
34|private:
35| tjs_int Value;
36|};
- 35行目
- 話が前後しますが、データメンバです。ネイティブインスタンスには、必要なデータメンバを自由に書くことができます。
- 4~8行目
- NI_Test のコンストラクタです。C++ クラスとしての初期化は 後述の Construct よりもここで済ませておき、Construct での初期化は最小限の物にすることをおすすめします。
この例では、データメンバの Value に初期値として 0 を設定しています。
- 10~20行目
- new 演算子で TJS2 オブジェクトが作成されるときに呼ばれます。numparams と param 引数は new 演算子に渡された引数を表しています。
tjs_obj 引数は、作成される TJS オブジェクトです。
この例では、引数があれば (さらにそれが void で無ければ )、それを Value の初期値として設定しています。
- 22~25行目
- オブジェクトが無効化されるときに呼ばれるメソッドです。ここに終了処理を書くと良いでしょう。
この例では何もしません。
- 27~32行目
- データメンバを操作するための公開メソッド群です。後述するネイティブクラス内で、これらを利用するコードを書きます。
オブジェクトを作成するためにはクラスが必要ですので、クラスを記述します。クラスは tTJSNativeClass を導出する形で実装します。tTJSNativeClass は iTJSDispatch2 インターフェースを持っていて、ネイティブクラスとして振る舞うための基本的な動作が実装されています。
TJS からアクセス可能なメソッドやプロパティは、ネイティブクラスのコンストラクタ内に記述します。
例:
1|class NC_Test : public tTJSNativeClass
2|{
3|public:
4| NC_Test();
5|
6| static tjs_uint32 ClassID;
7|
8|private:
9| tTJSNativeInstance *CreateNativeInstance()
10| {
11| return new NI_Test();
12| }
13|};
14|tjs_uint32 NC_Test::ClassID = (tjs_uint32)-1;
- 4行目
- このクラスのコンストラクタです。実装は後述します。
- 6行目
- このクラスのクラス ID を保持するための変数です。14行目に実体があります。
- 9~12行目
- CreateNativeInstance メソッドは、ネイティブインスタンスを作成すべきタイミングで呼ばれるメソッドです。ここでは NI_Test クラスのオブジェクトを作成して返しています。
例:
1|NC_Test::NC_Test() : tTJSNativeClass(TJS_W("Test"))
2|{
3| TJS_BEGIN_NATIVE_MEMBERS(Test)
4|
5| TJS_DECL_EMPTY_FINALIZE_METHOD
6|
7| TJS_BEGIN_NATIVE_CONSTRUCTOR_DECL(
8| _this,
9| NI_Test,
10| Test)
11| {
12|
13|
14| return TJS_S_OK;
15| }
16| TJS_END_NATIVE_CONSTRUCTOR_DECL(Test)
17|
18| TJS_BEGIN_NATIVE_METHOD_DECL(print)
19| {
20| TJS_GET_NATIVE_INSTANCE(_this,
21| NI_Test);
22|
23| _this->Print();
24|
25| return TJS_S_OK;
26| }
27| TJS_END_NATIVE_METHOD_DECL(print)
28|
29| TJS_BEGIN_NATIVE_METHOD_DECL(add)
30| {
31| TJS_GET_NATIVE_INSTANCE(_this,
32| NI_Test);
33|
34| if(numparams < 1) return TJS_E_BADPARAMCOUNT;
35|
36| _this->Add((tjs_int)*param[0]);
37|
38| return TJS_S_OK;
39| }
40| TJS_END_NATIVE_METHOD_DECL(add)
41|
42| TJS_BEGIN_NATIVE_PROP_DECL(value)
43| {
44| TJS_BEGIN_NATIVE_PROP_GETTER
45| {
46| TJS_GET_NATIVE_INSTANCE(_this,
47| NI_Test);
48| *result = _this->GetValue();
49| return TJS_S_OK;
50| }
51| TJS_END_NATIVE_PROP_GETTER
52|
53| TJS_BEGIN_NATIVE_PROP_SETTER
54| {
55| TJS_GET_NATIVE_INSTANCE(_this,
56| NI_Test);
57| _this->SetValue((tjs_int)*param);
58| return TJS_S_OK;
59| }
60| TJS_END_NATIVE_PROP_SETTER
61| }
62| TJS_END_NATIVE_PROP_DECL(value)
63|
64| TJS_BEGIN_NATIVE_PROP_DECL(square)
65| {
66| TJS_BEGIN_NATIVE_PROP_GETTER
67| {
68| TJS_GET_NATIVE_INSTANCE(_this,
69| NI_Test);
70|
71| *result = _this->GetSquare();
72|
73| return TJS_S_OK;
74| }
75| TJS_END_NATIVE_PROP_GETTER
76|
77| TJS_DENY_NATIVE_PROP_SETTER
78| }
79| TJS_END_NATIVE_PROP_DECL(square)
80|
81| TJS_END_NATIVE_MEMBERS
82|}
- 1行目
- NC_Test のコンストラクタです。親クラスである tTJSNativeClass のコンストラクタには TJS2 内で使用するクラス名を指定します。
- 3行目
- TJS_BEGIN_NATIVE_MEMBERS マクロです。引数には TJS2 内で使用するクラス名を指定します。
このマクロと TJS_END_NATIVE_MEMBERS マクロで挟まれた場所に、クラスのメンバとなるべきメソッドやプロパティの記述をします。
- 4行目
- 空の finalize メソッドを宣言しています。finalize に相当する処理は tTJSNativeInstance::Invalidate をオーバーライドすることでも実装できますので、通常は空のメソッドで十分です。
- 7~16行目
- (TJSの) コンストラクタを宣言しています。TJS でクラスを書くとき、クラス内でクラスと同名のメソッドを宣言している部分に相当します。
TJS_BEGIN_NATIVE_CONSTRUCTOR_DECL マクロの1番目の引数はネイティブインスタンスに割り当てる変数名で、2場面目の引数はその変数の型名です。この例でのこのブロック内では NI_Test * _this という変数が利用可能で、ネイティブインスタンスにアクセスすることができます。
マクロの3番目の引数は、TJS 内で使用するクラス名を指定します。TJS_END_NATIVE_CONSTRUCTOR_DECL マクロの引数も同様です。
ここも、コンストラクタに相当する処理は tTJSNativeInstance::Construct をオーバーライドする事で実装できるので、ここでは何もせずに S_OK を返します。
- 18~27行目
- print メソッドを宣言しています。メソッド名は TJS_BEGIN_NATIVE_METHOD_DECL と TJS_END_NATIVE_METHOD_DECL の両マクロに同じものを指定する必要があります。
このマクロ内で使用可能な変数に tjs_int numparams と tTJSVariant **param があって、それぞれ、渡された引数の数と引数を示しています。このメソッドではそれらは使用していません。
20~21行目は、オブジェクトからネイティブインスタンスを取り出すためのマクロです。この例では _this という NI_Test * 型の変数にネイティブインスタンスを取り出す、という意味になります。以降、_this という変数でネイティブインスタンスにアクセスできます。23行目で、そのネイティブインスタンスの Print メソッドを呼び出しています。
- 29~40行目
- add メソッドを宣言しています。ここでは numparams と param を使用しています。
- 42~62行目
- value プロパティを宣言しています。TJS_BEGIN_NATIVE_PROP_DECL と TJS_END_NATIVE_PROP_DECL の両マクロには、メソッドの宣言と同じく、プロパティ名を指定します。
TJS_BEGIN_NATIVE_PROP_GETTER と TJS_END_NATIVE_PROP_GETTER マクロで囲まれた場所には、ゲッターを記述することができます。ゲッター内では tTJSVariant 型である *result に値を設定するように記述します。
同様に、TJS_BEGIN_NATIVE_PROP_SETTER と TJS_END_NATIVE_PROP_SETTER マクロで囲まれた場所にはセッターを記述することができます。セッター内では tTJSVariant 型である *param に設定されるべき値が格納されているので、それを使って処理をします。
- 64~79行目
- ここでは読み出し専用プロパティを宣言しています。セッターの代わりに TJS_DENY_NATIVE_PROP_SETTER を書くことにより、読み出し専用プロパティを作ることができます。
ネイティブクラスの登録は、ネイティブ関数の登録と同じです。以下にテストコードを例示します。
例:
1| iTJSDispatch2 * global = tjsengine->GetGlobalNoAddRef();
2|
3|
4| iTJSDispatch2 *cls = new NC_Test();
5| tTJSVariant cls_var(cls);
6| cls->Release();
7|
8| TJS_THROW_IF_ERROR(
9| global->PropSet(TJS_MEMBERENSURE, TJS_W("Test"), NULL, &cls_var, NULL));
10|
11|
12| tjsengine->ExecScript(TJS_W(
13| "var test = new Test();\n"
14| "test.value = 5;\n"
15| "var test2 = new Test(test.square);\n"
16| "test2.add(3);\n"
17| "test2.print();\n\0"),
18| NULL, NULL, NULL);