さて、そろそろ皆さん、あのテンプレートがうざくなってきた所ではないでしょうか (爆)。結構面倒ですよね。あれ。
というわけで、今回はあのテンプレートを使わずに、プラグインを作ろうではないかという話です。
あのテンプレートが必要になるのは:
……くらいです ( うん、多いですよ? )。
実は、そこそこのことは Dll 呼び出しでもできます。これは厳密には HPI ではないのですが、他に正式な呼び名がないようなので、DllHPI とでも言っておきましょう。
さて、作り方です。まずはざっくりと簡単なモノを見てください。
#include <windows.h> EXPORT void WINAPI msgboxA(void) { MessageBoxA( 0, "Hello, world!", "dllhpi", MB_OK ); return; }
※DllMain() は省略できる、のか? なくても動いてしまうが。
このソースファイルだけでビルドできます ( 出力ファイルを test.hpi とします )。
次に、HSP側のヘッダを。
#ifndef IG_DLLHPI_TEST_AS #define IG_DLLHPI_TEST_AS #uselib "test.hpi" #func msgbox "msgboxA" // サンプル・スクリプト #if 1 msgbox #endif #endif
※ VC++ の場合は、"msgboxA" を "_msgboxA@0" とします。
実行。ふう、やはりいつも通りの始まり方ですね、これが。
……って、これただのDll呼び出しじゃん!!
ば、ばれたか…………。たしかに、これだけだと普通に dll 呼び出しただけです、はい。
ということは、DllHPI は Dll呼び出しの延長線上にある、ということです。
DllHPI と普通のDllの違いは、呼び出し引数にあります。引数によって、HPIでおなじみのあの構造体の方々が使用できます。
引数タイプ | 渡される型 | 指定すべきもの |
---|---|---|
pval | PVal* | 変数 |
bmscr | BMSCR* | (なし) |
prefstr | char[] | (なし) |
pexinfo | HSPEXINFO* | (なし) |
基本的に、「#func」のヘルプを見ればいいかと思います。
ちなみに、BMSCR 構造体は、いままで触れていませんでしたが、HSPのウィンドウを管理する構造体です。bmscr の引数は、操作先ウィンドウのそれへのポインタを渡します。これを使って、画面への描画やウィンドウの操作なども行えますので、後々やってみようと思っています。
新しくプラグインを考えるのも面倒なので、既存のモノをこの形式で作り直してみましょう。
varinfo でいいですか。いいですね。
今回のソースコードはここにあります:「varinfo (dllhpi版)」
// varinfo dllhpi #include <windows.h> #include "hsp3plugin.h" #include "varinfo.h" //------------------------------------------------ // varinfo() //------------------------------------------------ EXPORT int WINAPI varinfo( PVal* pvTarget, int type, HSPEXINFO* pExinfo ) { ::exinfo = pExinfo; switch ( type ) { case VARINFO_LEN0: return pvTarget->len[0]; case VARINFO_LEN1: return pvTarget->len[1]; case VARINFO_LEN2: return pvTarget->len[2]; case VARINFO_LEN3: return pvTarget->len[3]; case VARINFO_LEN4: return pvTarget->len[4]; case VARINFO_FLAG: return pvTarget->flag; case VARINFO_MODE: return pvTarget->mode; case VARINFO_PTR: { HspVarProc* vp = getproc( pvTarget->flag ); return reinterpret_cast<int>( vp->GetPtr(pvTarget) ); } default: puterror( HSPERR_ILLEGAL_FUNCTION ); } }
いつも通り "hsp3plugin.h" を結合していますが、PVal や HSPERROR などの定義はこれを使わないと分からないので、仕方がありません。
このせいで、グローバル変数 exinfo や ctx が定義されてしまうという困った事態にもなります。それらは、いつもは hspsdk_init() で初期化されていたので問題ないのですが、DllHPI ではそんなものないので、NULL です。危険です。
そこで、引数で受け取った HSPEXINFO* をセットしておきます。本当は不要ですが、これをすると puterror() などの、グローバル変数 exinfo を使用しているマクロが使えるようになります。だれも、pExinfo->HspFunc_puterror() なんて長ったらしいことはしたくないでしょう?
これのヘッダ varinfo.h は次の通りです。
// varinfo dllhpi #ifndef IG_VARINFO_DLLHPI_H #define IG_VARINFO_DLLHPI_H #include <windows.h> #include "hsp3plugin.h" // プロトタイプ宣言 EXPORT int WINAPI varinfo( PVal* pval, int type, HSPEXINFO* pExinfo ); // 定数 enum VARINFO { VARINFO_LEN0 = 0, VARINFO_LEN1, VARINFO_LEN2, VARINFO_LEN3, VARINFO_LEN4, VARINFO_FLAG, VARINFO_MODE, VARINFO_PTR, VARINFO_MAX }; #endif
この2つのファイルでビルドできます。出力ファイルは varinfo.hpi とします。
そして、HSP側のヘッダは次の通り。
// varinfo - public header #ifndef IG_VARINFO_HPI_AS #define IG_VARINFO_HPI_AS #uselib "varinfo.hpi" #cfunc global varinfo "_varinfo@12" pval,int, pexinfo // 定数 #enum global VARINFO_LEN0 = 0 #enum global VARINFO_LEN1 #enum global VARINFO_LEN2 #enum global VARINFO_LEN3 #enum global VARINFO_LEN4 #enum global VARINFO_FLAG #enum global VARINFO_MODE #enum global VARINFO_PTR #enum global VARINFO_MAX // サンプル・スクリプト #if 1 // 本当はもっと入念にテストしてください (>_<; a = 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024 mes "len1 : " + length(a) + "\t: " + varinfo(a(1), VARINFO_LEN1) mes "len2 : " + length2(a) + "\t: " + varinfo(a(1), VARINFO_LEN2) mes "len3 : " + length3(a) + "\t: " + varinfo(a(1), VARINFO_LEN3) mes "len4 : " + length4(a) + "\t: " + varinfo(a(1), VARINFO_LEN4) mes "ptr : " + varptr(a(1)) + "\t: " + varinfo(a(1), VARINFO_PTR ) mes "flag : " + vartype(a(1)) + "\t: " + varinfo(a(1), VARINFO_FLAG) mes "mode : " + "----" +"\t: " + varinfo(a(1), VARINFO_MODE) stop #endif
※インポート関数名 "_varinfo@12" は VC++ 2008 の場合です。BCC の場合は "varinfo" にしてください。
今回の varinfo は命令形式では使用できません。たぶん問題ないと思いますが、一応。
今回は趣向を変えて Dll 呼び出しバージョンを試してみました。
では、また次回。
by 上大