Home -> HSP講座 -> HPI編 No.01

作るだけ作ってみよう

さて、本格開発のはじまりはじまりー。
まずはタイトル通り、簡単に作ってみます。
どこぞやの講座と同じですが、メッセージボックスの表示です。( 怒られたらどうしよう )
msgbox という命令を追加します。パラメータはなく、ただダイアログを表示するだけです。


新規プロジェクトを作ろう

題の通りです。新規プロジェクトを作成して下さい。プロジェクト名は msgbox で、DLLです。
VC++ の人は、「空のプロジェクト」にチェックを入れてください。
それに加えて、HSPSDKの中のものも追加します。
if hsp3.1以前 { hspsdk31/sample/hpi3sample の hsp3plugin.cpphsp3plugin.h です。}
if hsp3.2     { hspsdk/hpi3sample の hsp3plugin.cpp と hsp3plugin.h です。 }
フィルタ・管理フォルダなるものを作れるので、そこにでも追加してやってください。

※BCC。赤丸のボタンをクリックして、管理フォルダにファイルをドロップ。
ほとんど同じなので、VC++の画像は省略します。

チーム開発では、一つのフォルダにすべてのファイルをまとめて置きますが、個人レベルでは、いちいちファイルをコピーする意味がありません。
そのため、先ほど追加したファイルは hspsdk の中においたままにします。
しかし、これでは include するとき不便です。そこで、インクルードパスを設定します。
BCC では、メニューバー/プロジェクト設定/[コンパイル3]タブです。
ついでに、[アプリケーション] で "ターゲット" を Dynamic Link Library(-WD) に変更しておいてください。
VC++では、「メニューバー/プロジェクト/msgbox のプロパティ」で、[構成プロパティ]/[C/C++]-[全般]/"追加のインクルードファイル" です。
どちらも「hsp3plugin.h のあるフォルダ」を選んでください。


メインのコードを書く

やっとコードが書けます。手がうずうずしてきたことでしょう。
dllmain.h というファイルを作って、プロジェクトに追加し、次のように書きます。
今回のコードは「msgbox リポジトリ」に公開しています。

ヘッダファイルですね……。とりあえず、windows.h と hsp3plugin.h を include しておきます。
※ windows.h を include しないと、hspsdk のファイルがコンパイルできない。

ちなみに、最初にある #ifndef, #define、最後の #endif は、3つ合わせてインクルードガードといい、ファイルの二重結合を防ぎます。
これがないといろいろ面倒なことになってしまうので、.h ファイルには必ず付けるようにしましょう。
.cpp の方は、include されないので付ける必要はありません。
マクロの名前「IG_MSGBOX_DLLMAIN_H」は、他のファイルと被らないなら何でもいいです。
ちなみに VC++ では「#pragma once」とだけ書いてもいいです。

さて、ついに dllmain.cpp です。

HSPSDKの機能をふんだんに使っててますね。以下でこれの解説をしていきます。


プラグインの実行方法(簡易版)

プラグインは、簡単に言うと、以下のとき、HSPと関わります。

プラグインの初期化は、HSPの実行より前に行われます。このとき、唯一の EXPORT される関数である、hsp3hpi_initが呼ばれます。
各拡張プラグインにはHSP3TYPEINFO構造体という、そのプラグインの情報をHSP側に教えるための構造体が1つずつ提供されます (引数の HSP3TYPEINFO* がそれへのポインタ)。
これのメンバに必要な情報 (主に関数ポインタ ← 後述) を設定するのが、この「初期化」です。

次に、「コマンド実行」です。コマンドとは、命令、関数、システム変数の3つを合わせた言い方です。
すべてのコマンドには、type 値と code 値というのが設定されています。
type 値は、そのコマンドがどのプラグインに属するものなのか、を表す番号です。具体的な値は後の回で説明します。
code 値は、プラグインがそのコマンドに割り当てる番号です。
たとえば上の例において、HSP は「msgbox 命令」のことを「18 番目のプラグイン」の「コード 0x000 の命令」と識別するわけです。

スクリプトというのはコマンド(とパラメータ)の列です。
コマンドを実行するときに HSP は、「type 番目のプラグイン」に「コード code のコマンド」を処理せよ、と命じます。
具体的に言うと、そのプラグインの HSP3TYPEINFO が持つ関数ポインタ cmdfunc, reffunc から、関数を呼び出します。上記のコードでは、命令なら cmdfunc が、関数かシステム変数なら reffunc が呼ばれます。
HSPが命令キーワードを処理する図

「割り込み」はしばらく無視します。

最後に「終了時」です。
HSPの実行が終わるとき (end命令を実行したときなど) に、HSP3TYPEINFO の termfunc メンバの関数を呼び出します。
しなければならないことはないので、不要なら設定しません。


Let's Build Plug-in!!

さて、上の一対のファイル (dllmain.cpp と dllmain.h) をプロジェクトに追加するだけでコンパイルできます。
mesbox.dll が作成されることでしょう。「.hpi」にしたければ、リネーム (名前の編集) をしてください。
hpiは Hsp Plug-In の略で、HSP3プラグイン独自の拡張子です。


HSPからプラグインを呼び出そう

HSPからプラグインを呼び出すには、プリプロセッサ命令 #regcmd と #cmd を使います。

// msgbox - public header

#ifndef IG_MSGBOX_AS
#define IG_MSGBOX_AS

#regcmd "hsp3hpi_init", "msgbox.dll"
#cmd msgbox 0x000  // コマンド msgbox をコード値 0x000 で登録

#endif

VC++の人は注意が必要です。
BCCの人はそのままでいいですが、VC++の人は "hsp3hpi_init""_hsp3hpi_init@4" に書き換えます。
名前修飾といって、VC++コンパイラは関数をそのまんまの名前にしないのです。

★名前修飾の確認
……と、名前修飾の結果だけ教えても意味がありませんので、一応確認します。
名前修飾の結果は、dll (hpi) の中をみると、簡単にわかります。
バイナリエディタで、関数名(hsp3hpi_init) を検索してみてください。
名前修飾の確認
※バイナリエディタは Stirling です。文字列での検索中。
開発環境のマニュアルやらドキュメントやらを見るのが本当の正攻法ですけれど。

#regcmd は、HSPからプラグインを使用することを宣言します。
初期化の時に呼び出す(正確な)関数名と、プラグインの名前を指定します。
#cmd は、プラグインのキーワードを宣言します。
上の例では、msgbox が 0x000 として、登録されます。
cmdfunc 関数の分岐で、msgbox の処理が 0x000 だったことを思い出してください。つまり、コマンド msgbox の code 値を決めているのです。(えぇ、同一の値なのに名前つき定数を使わないのかい!?)

さて、このファイルを msgbox.as というファイル名でプラグインと同じフォルダに置いてください。
そして、msgbox.as の最後の方に:

	msgbox

と追加し、実行してみてください。
メッセージボックスが表示されれば完成です!!


おわりに

駆け足でプロジェクト発足からプラグイン完成まで突き進みました。
今回の内容はHSP3プラグインを作成する際の基礎です。
次回以降も覚えておく必要ががありますが、何度も確認すればきっと慣れるでしょう。

作った命令 msgbox は非常におもしろみがないですが、その辺りは次回以降、ひとつひとつ解説していくつもりです。
では、また次回。


by 上大

序章へ   第二章へ