Home -> HSP講座 -> HPI編 DllHPI

DllHPI

さて、そろそろ皆さん、あのテンプレートがうざくなってきた所ではないでしょうか (爆)。結構面倒ですよね。あれ。
というわけで、今回はあのテンプレートを使わずに、プラグインを作ろうではないかという話です。


プラグインでできるもん

あのテンプレートが必要になるのは:

……くらいです ( うん、多いですよ? )。
実は、そこそこのことは 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呼び出しの延長線上にある、ということです。


特殊な #func 引数タイプ

DllHPI と普通のDllの違いは、呼び出し引数にあります。引数によって、HPIでおなじみのあの構造体の方々が使用できます。

DllHPI 用の引数タイプ
引数タイプ 渡される型 指定すべきもの
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 上大

第八章2へ   第十章へ