2013年8月31日土曜日

【なでしこ】プラグインDLLの中身

なでしこのDLLに含まれる(なでしこから呼ばれる)関数はそんなに多くなく、

・ImportNakoFunction
・PluginInfo
・PluginVersion
・PluginRequire
・PluginInit
・PluginFin

の6つです。この内、自分でせっせといじる必要があるのは

・ImportNakoFunction

で、この中で自分の作成した関数(命令)を登録します。 たとえば、なでしこから
DLLに渡ってくる引数のチェックをする関数を作ったとします。

------ここから------

 void _disp_nakovar(PHiValue pvar)
{
    if (pvar != NULL)
    {
        switch (pvar->VType)
        {
            case varNil :

                DBGPRINTF("Var is Nil(%d)\n", pvar->VType);
                break;
              
            case varInt :

                DBGPRINTF("Var is Int(%d)\n", pvar->VType);
                break;

            case varStr :

                DBGPRINTF("Var is Str(%d)\n", pvar->VType);
                break;

            default :
                DBGPRINTF("Var is Unknown(%d)\n", pvar->VType);
                break;
        }
    }
}

------ここまで------

あ、デバッグ用に作ったのでDBGPRINTF()とかなってますが、
中身はprintf()です。 PHiValuはなでしこの変数を格納するための
構造体(へのポインタ)で、これに変数の種類とかいろいろ書いて
ありあす。途中省略してますが、この構造体の中身みれば、
大体のことが分かります(…って言うか、なでしこからDLLに
渡される情報はこの構造体が全てです(^^; )。

このままではなでしこに登録できませんので、なでしこの命令と
して登録できる形の関数を書く必要があります。

------ここから------

PHiValue __stdcall dnako_varchk(DWORD h)
{
    PHiValue arg1 = 0;
    PHiValue ret = 0;
    NAKO_FUNCS *pfnako = _get_nako_funcs();

    DBGPRINTF("Enter -- %s()\n", __FUNCTION__);
  
    arg1 = pfnako->nako_getFuncArg(h, 0);

    ret = pfnako->nako_var_new(NULL);

    DBGVARCHK(arg1);
  
    return(ret);
}

------ここまで------

なでしこに登録する命令は常にこの形になっています。

PHiValue __stdcall dnako_varchk(DWORD h)

は、戻り値がPHiValue、Windowsの関数コール規約__stdcall、関数名が
dnako_varchk(これはユーザーが任意に名前つけられます)、引数は
DWORD型のh一つだけとなります。

命令の引数から実際の変数を取得する場合は

・pfnako->nako_getFuncArg(h, 0)

を使用します。pfnakoは関数セットを構造体として持っていて、
そこへのポインタです。この関数を実行することで、引数のh
から、PHiValueの変数を引っ張ってこれる仕組みです。

命令の引数が複数ある場合は、

arg1 = pfnako->nako_getFuncArg(h, 0);
arg2 = pfnako->nako_getFuncArg(h, 1);
arg3 = pfnako->nako_getFuncArg(h, 2);

と、引数分実行すれば順番に取得できます。つまりnako_getFuncArg()
の第二引数は、変数のリストだか配列だかのインデックスってこと
ですね。先頭のインデックスは0です。

こうやって取得したarg1はPHiValue型ですので、必要に応じてここから
整数や文字列を取り出します。pfnakoの中に、

・nako_var2int() /*PHiValueからint型の値取り出し*/
・nako_var2str() /*PHiValueから文字列取り出し*/

などがあるので、必要に応じて使用します。

最後に、この関数はデバッグ用だったので、戻り値は特に必要なかった
ですが、実際に必要な場合には、

・ret = pfnako->nako_var_new(NULL);

でPHiValue型の空の変数を作成した後、


・nako_int2var()

などを使用して、PHiValue型に実際をセットし、これをなでしこに返します。
すると、それがなでしこ命令を実行した際の戻り値になるわけですね~♪

最後はこのdnako_varchk()をなでしこに登録します。上でも書きましたが
登録するのは、

ImportNakoFunction()の中身でやります。

------ここから------

NAKO_API(void) ImportNakoFunction(void)
{
    NAKO_FUNCS *pfnako = _get_nako_funcs();
   
    DBGPRINTF("Enter -- ImportNakoFunction()\n");
   
    pfnako->nako_addFunction("DLL引数ダンプ", "A", dnako_varchk, 0);
}

------ここまで------

・pfnako->nako_addFunction("DLL引数ダンプ", "A", dnako_varchk, 0);

が実際に登録してる場所で、"DLL引数ダンプ"はなでしこの命令名、
"A"がその時の引数、 "dnako_varchk"が上で作ったCの関数名です。
最後の0は…分かりませんヾ(;´▽`A``。サンプルに0が設定されてたので
0にしてあります…。

なでしこ命令の引数ですが、"A"と書いた部分に"A,B"と書いておけば
引数が2つってことになります。またここに"Aの"とか書いておけば、
なでしこ命令としても「AのDLL引数ダンプ」みたいに書けます。上の
場合は

・DLL引数ダンプ(A)

と、ちょっとC言語っぽくなりますが、今回は引数が多めの命令も
ありますので、これで統一します。