プラグインに挑戦してみた

HSP3用のプラグイン作成に挑戦してみました。
C++やプラグイン作成に詳しくない方は、導入の資料に、
C++やプラグイン作成に詳しい方は、「何をいまさら」と心の中で突っ込みを入れつつお楽しみ下さい。

開発環境

用意するもの。

OS Vista
ソフト Visual C++ 2008 Express Edition
その他 HSP3SDK

VC++2008EEはフリーなので簡単に手に入ります。いやー、いい世の中になったもんだ。
ちなみにVC++2005EEだとPlatform SDKを別途入手する必要あります。
導入方法は各自ぐぐってください。

プラグイン

とりあえずC++で「Hello,World!」が出せる程度に使えるようになったところで、プラグインに着手。

…と、ちょうどいいタイミングというか、どっかで見てるんじゃないかというタイミングで fさんがdllスレを立ててくれました。
早速参考にしつつ試行錯誤でプラグイン作成テスト…あっさり成功。(多少は調べましたけどね。)
(ログあさってください。)

でもこれ一般のdllの作り方でした。
このまま進めてもいいのですが、将来的にHSPからの情報の受け渡しがしやすいであろう HSP専用プラグインを作ってみることにしました。(難しかったら速攻であきらめる事前提で。)


ということで再度調査開始。とりあえずHSP3SDKのなかにマニュアルhspdll.txtが入っているわけですが…、
読んで作れるくらいならもっと前からやってるよ。orz
と言うわけで講座系サイトの出番です。

とりあえずgoogle先生に質問してみたところ
プログラ広場(http://prograpark.ninja-web.net/)
が、よさそうとの回答。
今後はここを参考に作っていくことにしました。


ここまでの成果をまとめたものがここ↓にあるので参照ください。
HSP開発wiki - MakeHPI/VC++
http://hspdev-wiki.net/?MakeHPI%2FVC%2B%2B
といってもwikiなので他の方が加筆訂正してくださっているかもしれませんのであしからず。

ポインタ

講座サイトを読みながら実践してみると、ポインタを追いかけられずに行き詰ってしまいました。
どうやら基本ぐらいは理解していたつもりのポインタ、理解が不足していた様子。
この時点のポインタへの理解度は…

「ポインタには、変数の値が格納されてる場所のアドレスが入ってるんだよね。」
「で、それってなんの役に立つの?」

こんな感じでした。
どうやらこれではダメらしいのでgoogle先生に聞いてみた。

奮闘記:その36
C言語のポインタって何?
10年かけて越えたポインタの壁
http://www.geocities.jp/sugachan1973/doc/funto36.html

タイトルからしていい感じ。
ちょっと長いですが読んでみたらよく理解できました。(という気がする。)
最近出てきた*_sがセキュリティーホールだとか何とかという話もなんとなく分かった気になれました。

…まあ、こういうのは時間かけてなれていくことにします。

という感じでポインタについてはひとまず解決。

構造体とメンバ関数

ポインタはなんとかなった気がしたものの、「構造体って関数持てたの?」なんてところで行き詰る。
昔読んだ本で「classの特徴は構造体と違い関数を持てること」みたいなことを読んだ記憶があったので 構造体が関数持ったらclassの意味ないよなーと(?_?)となってしまいました。
google先生いわく。
構造体もメンバ関数もてんねんで。とのこと。
http://homepage2.nifty.com/aito/cpp/node5.html
http://wisdom.sakura.ne.jp/programming/cpp/cpp44.html
いくつか読んでみると、構造体は残したいものの、自由に新しい機能を付け加えられるよう新規にclassを作った、のではないか? という話が見られました。事実かどうかはわかりませんが。

と、いう感じでこの問題もひとまずクリア…かな?

配列変数の入出力

簡単な値の受け渡しは、サンプルや講座を見ながらで何とかなったものの、 配列変数はちょっと時間かかってしまいました。
ポインタとメンバ関数について調べる時間がほとんどだった気がしますが…。しかも完全に理解できたわけじゃない。

でもとりあえず配列変数を扱えるようになったのでサンプルを上げておきます。
何かの参考になれば。

static void usertest( void )
{
	//		usertest 命令の処理
	//
	//		usertest 配列変数1,配列変数2,配列変数3,配列変数4
	//		配列変数3 = 配列変数1
	//		配列変数4 = 配列変数2 * 100
	//

	//
	//	引数に指定した変数を使用する準備
	//
	PVal *pval1, *pval2, *pval3, *pval4;
	APTR aptr1, aptr2, aptr3, aptr4;

	//配列変数の取得
	aptr1 = code_getva( &pval1 );						// 変数の取得(PValとAPTRポインタ)
	aptr2 = code_getva( &pval2 );
	aptr3 = code_getva( &pval3 );
	aptr4 = code_getva( &pval4 );

	//	入力変数の型と実体のポインタを取得
	HspVarProc *phvp1, *phvp2;
	void *ptr1, *ptr2;
	int *p1, *p2;	//配列変数の先頭ポインタ

	phvp1 = exinfo->HspFunc_getproc( pval1->flag );	//型を処理するHspVarProc構造体へのポインタ
	ptr1  = phvp1->GetPtr( pval1 );					//データ(pval1)の実態がある先頭ポインタを取得。
	p1 = (int *)pval1->pt;							//実際の配列変数へのポインタ

//	phvp2 = exinfo->HspFunc_getproc( pval2->flag );
	phvp2 = getproc( pval2->flag );
	ptr2  = phvp2->GetPtr( pval2 );
	p2 = (int *)pval2->pt;

	//	出力用配列変数を初期化する
	//		dim 配列変数, 4
	exinfo->HspFunc_dim(pval3, HSPVAR_FLAG_INT, 0, 4, 0, 0, 0);
	exinfo->HspFunc_dim(pval4, HSPVAR_FLAG_INT, 0, 4, 0, 0, 0);

	HspVarProc *phvpint3, *phvpint4;
	phvpint3 = getproc( HSPVAR_FLAG_INT );	//int型のHspVarProc構造体
	phvpint4 = getproc( HSPVAR_FLAG_INT );


	//
	//	データの読み込み
	//

	// 変数データを varinfo に、一時的に格納
	int i;
	int verout[4];
	for(i=0;i<4;i++) {
		verout[i] = p2[i]*100;
	}

	//
	//	データの書き込み
	//

	// データを pval3,4 の配列に格納する
	for(int i = 0; i < 4; i ++) {
		pval3->offset = i;			//配列データpval3のオフセット
		phvpint3->Set( pval3, phvpint3->GetPtr(pval3), &p1[i] );	//代入

		pval4->offset = i;			//配列データpval4のオフセット
		phvpint4->Set( pval4, phvpint4->GetPtr(pval4), &verout[i] );	//代入
	}
}
解説は…望まないでください。orz
適切な説明が出来るほどのレベルに達してませんので。
実装するときは自己責任でお願いします。

hspdll.hs

いろいろ調べながら作業やってきたんですが、その過程でhspdll.txtを活用するためhspdllをhs化してみました。
無理やりなので使い勝手は多少不備がありますが、検索や関連項目の引き出しの時間が短縮できていい感じです。
作ったものはHSP開発wikiにupしましたので興味あればご利用ください。
HSP開発wiki - MakeHPI / hspdll
http://hspdev-wiki.net/?MakeHPI%2Fhspdll


なお、hspdll.txtはプラグイン作成の全てを網羅しているわけではありません。
hspdll.txtにかかれてない部分はサンプルを解読するほかありません。

私の場合サンプルの読解力が無いため、現在重度の情報不足。orz
どうしたものか。