[Top Page][Edit][Discussion][Edit History][All Pages][Recent Changes][->Japanese]

HSP2.6:HSPDLL

  1. VCLを使わない時は、makファイル内のALLLIB行にあるvcl.lib を削除、そしてcp32mt.lib を cw32mt.libに変更する。さらに、最初にインクルード指定されている「#include 」を削除し、かわりに「#include 」を記述する。
  2. C++ Builder 3.0の場合は2.のmakファイルがbprファイルになっているので注意が必要です。また、bprファイル内のALLOBJ行にある、「sysinit.obj も削除してください。
  3. マルチスレッドを使用しない場合は、リンクするライブラリをcw32mt.libではなくcw32.libにすることで、さらに少しサイズの節約ができます。
  4. 最終コンパイル時は、プロジェクトオプションのスピードを「リリース」のモードにしておく。

各タイプに応じた関数の作成

以下のような形式で関数を作成してください。 EXPORT BOOL WINAPIはすべてのタイプで共通の宣言です。 また、関数が正常に終了した場合には、 必ず「return 0;」のように0を 返してください。 ここで、0以外の値を返すとHSPはエラーメッセージを表示 します。 (戻り値の詳細は、「戻り値の設定について」をご覧ください)

        EXPORT BOOL WINAPI test ( int p1, int p2, int p3, int p4 )
        {
        //  start
        //   :
        //  end
        return 0;
        }
タイプ0 : 新規命令 p1,p2,p3,p4
    ( p1=int, p2=int, p3=int, p4=int )
    [ test( int p1, int p2, int p3, int p4 ); ]

このタイプは、intの引数4つが渡されます。すべて32bit signed int です。値が省略されている場合は0が渡されます。

タイプ1 : 新規命令 p1,p2,p3,p4
    ( p1=変数バッファへのポインタ, p2=int, p3=int, p4=int )
    [ test( void *p1, int p2, int p3, int p4 ); ]

このタイプは、p2〜p4まではタイプ0と同じ32bit signed intです。 p1だけは、変数のバッファへのポインタになります。 つまり、HSP側では、「test a,2,3,5」のように最初に変数名が記述されていることが前提になります。

p1には、指定された変数の内容が格納されているメモリへのポインタが入ります。 数値型変数であれば、「*(int *)p1」がその内容になり、変数の内容を直接書き換えることができます。

文字列型変数や、配列変数の場合はメモリのポインタから先にデータ が順番に格納されています。

文字列であれば、1byte単位で0x0が最後 のデータを表わすCストリング形式(null terminated strings)になって います。 DLL側から値を返したり、文字列を返す時にはこのタイプを使います。

タイプ2 : 新規命令 p2,p3,p4
    ( p1=BMSCR構造体へのポインタ, p2=int, p3=int, p4=int )
    [ test( BMSCR *p1, int p2, int p3, int p4 ); ]

このタイプは、HSP側ではp2〜p4までの3つのパラメータを取ります。 p2〜p4はタイプ0と同じ32bit signed intです。

p1は、HSPで使用している画面に関する情報を含むBMSCR構造体が格納されているメモリへのボインタが入ります。 BMSCR構造体の詳細については別項で解説しています。

タイプ3 : 新規命令 p1,p2,p3,p4
    ( p1=変数のPVAL構造体へのポインタ, p2=int, p3=int, p4=int )
    [ test( PVAL *p1, int p2, int p3, int p4 ); ]
タイプ$83 : 新規命令 p1,p2,p3,p4
    ( p1=変数情報PVAL2構造体へのポインタ, p2=int, p3=int )
    [ test( PVAL2 *p1, int p2, int p3, int p4 ); ]

このタイプは、p2〜p4まではタイプ0と同じ32bit signed intです。 p1だけは、指定した変数の情報を格納する構造体(PVALまたはPVAL2) へのポインタになります。 HSP側では、「test a,2,3,5」のように最初に変数名が記述されて いることが前提になります。 PVAL構造体の詳細については別項で解説しています。

タイプ4 : 新規命令 p1,p2,p3,p4
    ( p1=int, p2=str, p3=int, p4=int )
    [ test( int p1, char *p2, int p3, int p4 ); ]
タイプ5 : 新規命令 p1,p2,p3,p4
    ( p1=変数バッファへのポインタ, p2=str, p3=int, p4=int )
    [ test( void *p1, char *p2, int p3, int p4 ); ]
タイプ6 : 新規命令 p2,p3,p4
    ( p1=BMSCR構造体へのポインタ, p2=str, p3=int, p4=int )
    [ test( BMSCR *p1, char *p2, int p3, int p4 ); ]
タイプ7 : 新規命令 p1,p2,p3,p4
    ( p1=変数のPVAL構造体へのポインタ, p2=str, p3=int, p4=int )
    [ test( PVAL *p1, char *p2, int p3, int p4 ); ]
タイプ$87 : 新規命令 p1,p2,p3,p4
    ( p1=変数情報PVAL2構造体へのポインタ, p2=str, p3=int )
    [ test( PVAL2 *p1, char *p2, int p3, int p4 ); ]

これは、タイプ0〜3のp2パラメータが文字列になったものです。 p2には、文字列データへのポインタが渡されることになります。

タイプ+$10
    ( p1=??, p2=??, p3=??, p4=refstr )
    [ test( … , char *p4 ); ]

それぞれのタイプに+$10する(bit4を立てる)と、 p4のパラメータがなくなりかわりにp4はシステム変数refstrへのポインタが渡されます。

つまり、p1,p2,p3のパラメータまではそれぞれのタイプと同じで、 p4だけが システム変数refstrへのポインタ(char *)になります。

これは、結果を文字列としてシステム変数に返したい時などに使用します。 (システム変数refstrには、4096文字までの文字列しか代入できませんので注意してください)

タイプ+$20
    ( p1=??, p2=??, p3=??, p4=dpminfo )
    [ test( … , char *p4 ); ]

それぞれのタイプに+$20する(bit5を立てる)と、 p4のパラメータがなくなりかわりにp4はHSPのファイルシステム値dpminfoへのポインタが渡されます。

つまり、p1,p2,p3のパラメータまではそれぞれのタイプと同じで、p4だけが dpminfoへのポインタ(char *)になります。

dpminfoは、DPMファイルやEXEに埋め込まれたファイルにアクセスする場合に 必要になるポインタ値です。 dpminfoについての詳細は、HSPサポートルーチンズ のソースファイル(hspsdk.cpp)を参照してください。

なお、dpminfoのポインタは、システム変数refstrと共用されているので、 dpminfoの値を使って初期化した後は、dpminfoポインタをシステム変数refstrへ代入するポインタとして自由に使ってかまいません。

タイプ+$30
    ( p1=??, p2=??, p3=??, p4=rgbptr )
    [ test( … , char *p4 ); ]

それぞれのタイプに+$30する(bit4,5を立てる)と、 p4のパラメータがなくなりかわりにp4はHSPのパレットrgbptrへのポインタが渡されます。

つまり、p1,p2,p3のパラメータまではそれぞれのタイプと同じで、p4だけがrgbptrへのポインタ(char *)になります。 rgbptrは、現在選択されているパレットの内容を指すポインタです。

この内容を書き換えることで、現在のパレットを変更することが可能です。 パレットデータは、rgbptrからR,G,Bの順に1バイトづつ輝度のデータが収められており、 これが色の数だけ(通常は256色)続いているだけです。 このデータを書き換えた後は、 実際のパレットに反映するためにいくつかの処理を行なわなければなりません。

これについては、HSPサポートルーチンズのソースファイル(hspsdk.cpp)を参照してください。

タイプ+$100

それぞれのタイプに+$100する(bit8を立てる)と、その関数はクリーンアップ関数に指定されます。 クリーンアップ関数は、HSPのプログラムが終了する時に自動的に実行されます。 これは、途中でHSPのプログラムを強制的に終了されたり、エラーで終了した時などに、 DLL側で確保したメモリやリソースが解放されなくなるのを防止するのに有効です。

DLL側でメモリやリソースを初期化しておいても、それを解放するための関数を、 このクリーンアップ関数に指定しておけば、どんな時に終了しても解放ルーチンが呼び出されることになります。

ただし、解放するルーチン側では、確保される前に呼ばれたり、2度呼び出されてもいいようにチェックを行なっておいてください。

タイプ$202 (新規)

タイプに$202を指定すると、ver2.6以降専用の新しい呼び出し規約に基づいた関数として指定されます。 タイプ$202は、パラメーターの解析をプラグインDLLの内部で行ないます。 これにより、 パラメーターの組み合わせや数の制限なく値を取得することが可能になります。

ver2.6以降に対応したプラグインを作成される方は、なるべくこのタイプを使って作成することを推奨致します。

また、HSPの今後のバージョンでもタイプ$202は、継続してサポートする予定です。

タイプ$202は、p1パラメーターとしてHSPEXINFO構造体へのポインタを渡します。 p2,p3,p4のパラメーターは、将来の拡張用で現在は未使用です。 HSPEXINFO構造体には、HSPから取得できる情報や、関数群がすべて収められています。

typedef struct HSPEXINFO
{
        //              HSP internal info data (2.6)
        //
        short ver;              // Version Code
        short min;              // Minor Version
        //
        int *er;                // Parameter Error Flag
        char *pstr;             // String Buffer (master)
        char *stmp;             // String Buffer (sub)
        PVAL2 **pval;   // Master PVAL ptr.
        //
        int *actscr;    // Active Window ID
        int *nptype;    // Next Parameter Type
        int *npval;             // Next Parameter Value
        int *strsize;   // StrSize Buffer
        char *refstr;   // RefStr Buffer
        //
        int (*HspFunc_prm_getv)( void );
        int (*HspFunc_prm_geti)( void );
        int (*HspFunc_prm_getdi)( int defval );
        char *(*HspFunc_prm_gets)( void );
        char *(*HspFunc_prm_getds)( char *defstr );
        int (*HspFunc_val_realloc)( PVAL2 *pv, int size, int mode );
        int (*HspFunc_fread)( char *fname, void *readmem, int rlen, int seekofs );
        int (*HspFunc_fsize)( char *fname );
        void *(*HspFunc_getbmscr)( int wid );
        int (*HspFunc_getobj)( int wid, int id, HSPOBJINFO *inf );
        int (*HspFunc_setobj)( int wid, int id, HSPOBJINFO *inf );
        //
} HSPEXINFO;

タイプ$202は、パラメーターの取得をユーザーの関数内で行ないます。

HSPSDK/SAMPLEディレクトリに、いくつかタイプ$202のサンプルがありますので、 そちらも参照してください。 以下は、整数値を3つ取得する例です。

EXPORT BOOL WINAPI test( HSPEXINFO *hei, int p1, int p2, int p3 )
{
        //      DLL test (type$202)
        int ep1,ep2,ep3;
        ep2 = hei->HspFunc_prm_getdi(0);                // パラメータ1:数値
        ep3 = hei->HspFunc_prm_getdi(0);                // パラメータ2:数値
        ep4 = hei->HspFunc_prm_getdi(0);                // パラメータ3:数値
        if ( *hei->er ) return *hei->er;                // エラーチェック
        return 0;
}

HspFunc_prm_getdi関数により、32bit整数値を取得することができます。 また、引数としてデフォルトの数値を指定することができます。

デフォルト数値を許さない場合は、HspFunc_prm_geti関数を使用してください。

HspFunc_prm_getdiの返り値が、実際のパラメーターとなります。 パラメーターは、 何個でも連続して取得することができます。 必要なパラメーターを取得したら、 最後にエラーチェックを行なう必要があります。 HSPEXINFOの「*er」メンバの内容が0ならば、

パラメーター取得中にエラーは発生していません。 内容が0以外の場合は、 それをそのままreturn値にして戻って下さい。エラーが報告されます。

エラーチェックを行なわないと、エラーが表示されなかったり、 動作がおかしくなる可能性があるので、忘れずに入れるようにしてください。

以下は、文字列や変数を取得する例です。

EXPORT BOOL WINAPI test( HSPEXINFO *hei, int p1, int p2, int p3 )
{
        //      DLL test (type$202)
        PVAL2 *pval;
        char *ep1;
        char *ep2;
        ep1 = (char *)hei->HspFunc_prm_getv();  // パラメータ1:変数
        pval = *hei->pval;                      // 変数のPVAL2ポインタを取得
        ep2 = hei->HspFunc_prm_gets();          // パラメータ2:文字列
        if ( *hei->er ) return *hei->er;        // エラーチェック
        return 0;
}

HspFunc_prm_getv関数は、変数のポインタを取得します。 HSPEXINFOの「*pval」メンバに取得した変数のPVALポインタが代入されます。 また、HspFunc_prm_getv関数自体の戻り値には、変数のデータそのもののポインタが入ります。

もし、配列変数を指定していた場合は、指定した配列のデータポインタが返ります。 たとえば、「a.2」という変数が指定されている場合は、PVALポインタは変数aそのもののPVAL情報になり、

HspFunc_prm_getv関数の返り値は、「a.2」のデータそのものが格納されているポインタとなります。

また、HspFunc_prm_gets関数は、文字列のパラメーターを取得します。 HspFunc_prm_gets関数の返り値は、文字列データへのポインタになります。

注意しなければならないのは、ここで返される文字列データへのポインタは、 HSP内部の一時的な文字列バッファであり、内容がずっと保持されるわけではありません。

たとえば、HspFunc_prm_gets関数の後に、もう一度HspFunc_prm_gets関数を 呼び出せば、 前の文字列バッファの内容は新しい文字列で上書きされてしまいます。 このため、文字列データを2つ以上取得したい場合には、 最初の文字列データをあらかじめコピーして保存しておく必要があります。

文字列は最大で64K(65536byte)まで渡される可能性があります。 また、文字列をコピーして保存しておくエリアとしてHSPEXINFOの「stmp」を 使用することができます。 ちなみに、デフォルトの文字列を設定できるHspFunc_prm_getds関数も同様の 動作を行ないます。

HSPEXINFO構造体の詳細は、以下の通りです。

        short ver;              // Version Code

HSPのバージョンコードが入ります。2.6の場合は、0x0206となります。

        short min;              // Minor Version

HSPのマイナーバージョン番号が入ります。

        int *er;                // Parameter Error Flag

エラーチェック用のフラグ値

        char *pstr;             // String Buffer (master)

HspFunc_prm_gets、HspFunc_prm_getds関数で取得される文字列バッファ。(64K)

        char *stmp;             // String Buffer (sub)

文字列バッファのコピー用に用意されたテンポラリメモリ(64K)。

        PVAL2 **pval;   // Master PVAL ptr.

HspFunc_prm_getvで取得される変数のPVALポインタ。

        int *actscr;    // Active Window ID

現在の操作先ウインドゥID。

        int *nptype;    // Next Parameter Type

次のパラメーターのタイプを示す変数のポインタです。*nptype値が、0の場合は記号、 1は数値、2は文字列、3はラベル名、4は変数名を示しています。

        int *npval;             // Next Parameter Value

次のパラメーターのタイプに対応した値を示す変数のポインタです。 *npval値は、 タイプ(nptype)に対応した値が代入されます。

        int *strsize;   // StrSize Buffer

システム変数strsizeへのポインタが格納されます。

        char *refstr;   // RefStr Buffer

システム変数refstrへのポインタが格納されます。

        int (*HspFunc_prm_getv)( void );

パラメーター取得用関数。変数ポインタを取得する。 返値は、変数のデータポインタ。

        int (*HspFunc_prm_geti)( void );

パラメーター取得用関数。整数値を取得する。 返値は取得した値。

        int (*HspFunc_prm_getdi)( int defval );

パラメーター取得用関数。整数値を取得する。 defvalでデフォルトの値を設定する。 返値は取得した値。

        char *(*HspFunc_prm_gets)( void );

パラメーター取得用関数。文字列を取得する。 返値は取得した文字列ポインタ。

        char *(*HspFunc_prm_getds)( char *defstr );

パラメーター取得用関数。文字列を取得する。 defstrでデフォルトの文字列を設定する。 返値は取得した文字列ポインタ。

        int (*HspFunc_val_realloc)( PVAL2 *pv, int size, int mode );

pvで指定PVALポインタの変数バッファを、sizeで指定したメモリサイズに変更する。 modeが0の場合は、メモリ空間を0で初期化、modeが1の場合は内容は変更せずにバッファサイズのみ変更します。

        int (*HspFunc_fread)( char *fname, void *readmem, int rlen, int seekofs );

fnameで指定したファイル名の内容を、readmemポインタのメモリに読み込みます。 rlenで読み込むサイズ(バイト単位)、 seekofsで読み込み開始オフセット(先頭から何バイト目か)を設定することができます。

PACKFILEに格納されているファイルや、暗号化されたファイルを取り出すことが可能です。 返値は実際に読み込まれたサイズとなります。ファイルがなかった場合は、マイナス値が返ります。

        int (*HspFunc_fsize)( char *fname );

fnameで指定したファイルのサイズを返します。 ファイルがなかった場合は、マイナス値が返ります。

        void *(*HspFunc_getbmscr)( int wid );

widで指定したウインドゥIDのBMSCR構造体ポインタを返値として取得します。

        int (*HspFunc_getobj)( int wid, int id, HSPOBJINFO *inf );

widで指定したウインドゥID内の、idで指定したオブジェクトIDの情報をHSPOBJINFO構造体に取得します。 正常に取得された場合は、0が返されます。

        int (*HspFunc_setobj)( int wid, int id, HSPOBJINFO *inf );

widで指定したウインドゥID内の、idで指定したオブジェクトIDの情報をHSPOBJINFO構造体から設定します。 正常に設定された場合は、0が返されます。

HSP ver2.6でサポートされている引数のタイプは以上ですべてです。

戻り値の設定について

DLLとしてHSPから呼び出される関数は、正常に終了した場合は必ず「return 0;」で、 0の値を返すようにしてください。 戻り値には以下の仕様が定められています。

戻り値 行なわれる処理
0 正常終了
-1以下 システム変数statに戻り値を代入して終了
1〜255 エラーを表示して停止
0x10000〜0x1ffff 終了後awaitを実行
0x20000〜0x3ffff 終了後waitを実行

戻り値に、1〜255の値を返すとその値をエラーコードとしてエラーが出力されます。 DLL内部でのエラーや、渡された値が正常でない場合などにエラーを出力したい時に使用してください。

また、 戻り値に、-1以下の負の値を返すとその値はシステム変数statの値として取り出され、 正常終了されます。 この場合は、正の値に変換され(-1ならば1、-5なら5のように)システム変数に代入されます。

エラーは出力されません。関数の細かい実行状況や、結果を示す値としてスクリプトに渡す際に有効です。

戻り値が0x10000〜0x1ffffの範囲にある場合は、(戻り値-0x10000)の値をパラメータとする、 await命令を直後に実行します。同様に、戻り値が0x20000〜0x3ffffの範囲にある場合は、 (戻り値-0x20000)の値をパラメータとする、 wait命令を直後に実行します。

これは、メッセージループやウインドゥの更新などを、DLLの命令実行後に強制的に行なうためのものです。

また、DLLではもう1つシステム変数refstrに文字列を返す方法が用意されています。 詳しくは、タイプ+$10の関数作成を参照してください。

関数を作成する上での注意点

DLLの関数は、HSPに追加した命令が実行される時に呼び出されます。 もし、DLLの関数内で長くループすることがあると、Windows全体のタスクを奪ってしまうので、 なるべく早く帰るように心がけてください。

なるべく早くと言っても、別に最適化をしなければいけないということではなくて、 何秒もDLL関数内にとどまっていないのであればOkです。

たとえば、ゲームのメインループをDLL内で作成するようなことは避けてください。 一定時間ごとに呼び出される関数を作る場合には、必ずHSP でメインループを作り、 await命令などでウエイトを入れながらDLLを呼び出すようにしてください。

これは、Windowsアプリケーションのお約束なので不自由かもしれませんが、 タスクマネージヤに「応答なし」と判断されないようにするためにも、守った方がいいでしょう。

プラグイン互換性について(新規)

ver2.6以降のプラグインでは、新規に追加された呼び出しタイプ$202を使用することを推奨致します。

将来のバージョンとなるHSP 3.0以降では、 内部データが変更されるためver2.4g〜ver2.55までで使用されていた呼び出しタイプを 完全にはサポートできない可能性があります。

HSP 3.0以降でも、継続してプラグインを対応するため以下の仕様に沿って作成して頂けると嬉しいです。

  • PVAL2構造体を使用する(PVAL構造体を使用しない)
  • BMSCR構造体は、flagからcolorまでのメンバのみ参照する
  • オブジェクトの参照、設定は、HspFunc_getobj、HspFunc_setobjを使用する

これらの仕様で作られたプラグインは、将来のバージョンでも極力互換性を維持する予定です。

PVAL構造体の詳細

PVAL構造体は、ver2.5以降に変更されたため、2種類のフォーマットが 存在します。

  • 呼び出しタイプ3,7 = PVAL構造体 ( ver2.4g以降で使用できるもの )
  • 呼び出しタイプ$83,$87 = PVAL2構造体 ( ver2.5以降で使用できるもの )

HSP ver2.5より以前のバージョンで動作させるためには、PVAL構造体を 使用してください。 ver2.5では、PVAL構造体、PVAL2構造体ともに使用する ことができますが、 なるべく新しい形式(PVAL2構造体)に対応したものを 推奨します。

PVAL,PVAL2構造体はhspdll.hで以下のように定義されています。

typedef struct PVAL2
{
        //              Memory Val structure (ver2.5 Type)
        //
        short   flag;                           // type of val
        short   mode;                           // mode (0=normal/1=clone/2=alloced)
        int     len[5];                         // length of array 4byte align (dim)
        int     size;                           // size of Val (not used)
        char    *pt;                            // (direct val) or (ptr to array)
} PVAL2;

typedef struct PVAL
{
        //              Memory Val structure (Old Type)
        //
        short   flag;                           // type of val
        short   mode;                           // mode (0=normal/1=clone/2=alloced)
        short   len[5];                         // length of array 4byte align (dim)
        short   version;                        // version check code (2.4 = 0)
        char    *pt;                            // (direct val) or (ptr to array)
        PVAL2   *realptr;                       // real ptr to ver2.5 PVAL
} PVAL;

それぞれのメンバには、HSPが管理する変数についての情報が格納されています。 1つの変数名につき1つのPVAL構造体が存在します。 これには、 変数の持つ属性や型などすべての情報が格納されています。 DLLでは、これらの値を自由に書き換えて使用することが可能です。

PVALとPVAL2の大きな違いは、変数情報として格納されているバッファサイズの情報が、 PVALでは16bit(short)であるのに対して、PVAL2では32bit(long) に拡張されている点です。 これは、HSP ver2.5以前では、配列変数の要素数として16bitを越える範囲を扱うことができなかった問題に対応したものです。 しかし、構造体が大きく変わってしまったため、 DLLでは以前との互換タイプ(PVAL)と新タイプ(PVAL2)を選んで使用してもらうことになってしまいました。

HSP内部では、PVAL2構造体が使用されており、DLLの呼び出しタイプでPVAL2構造体が指定されている場合は、 そのままポインタが渡されます。 DLLの呼び出しタイプで、PVAL構造体が指定されている場合には、 一旦 PVAL構造体に変換した後にそのポインタが渡されます。この場合は、配列の範囲(len)は16bitに切り詰められます。 また、PVAL構造体の中で 書き換えられる情報は、flag情報(変数型情報)に限られます。

以上のことからも、PVAL構造体を使う場合はオーバーヘッドが大きいだけでなく、 扱う情報が限られてしまうことが考えられるので、できればPVAL2構造体を使用することをお勧めします。

もし、オーバーヘッドを気にしないのであれば、現在のHSPがver2.5以降のPVAL2を使えるかどうかをDLL側から調べて、 PVALとPVAL2の両方に対応したDLLを作成することも可能です。 (詳しくは、versionとrealptrメンバの解説を参照してください)

それぞれのメンバの詳細は以下の通りです。

        short   flag;           // type of val (2=str/4=num)

変数の型が格納されています。 2ならば文字列型、4ならば数値型です。 これ以外の数値は無効な変数となります。

        short   mode;           // mode (0=normal/1=clone/2=alloced)

変数が作成されたモードが格納されています。 0ならば通常の変数、1ならばdup命令で作成されたクローンの変数、 2ならばalloc命令または、大きなメモリ空間を確保している変数を 示しています。

        int     len[5];         // length of array 4byte align (dim)

配列のサイズについての情報が格納されています。 dim p1,p2,p3,p4とした場合に、p1がlen[1]に、p2がlen[2]に、 p3がlen[3]に、p4がlen[4]の値となり保持されています。 PVALとPVAL2構造体では、サイズが異なっているので注意してください。

        char    *pt;            // ptr to Val

実際の変数の内容が記憶されているメモリへのポインタです。 配列変数であれば、ここで指定されたアドレスから連続的な空間が配列のために 確保されています。

        int     size;                           // size of Val (not used)

変数が使用しているメモリサイズの合計です(未使用)。 これは将来のバージョンで使用するために確保されているものです。 ver2.5現在は使用されていません。DLL側で使用することもできますが、 将来のバージョンでの動作は保証されません。

        short   version;                        // version check code (2.4 = 0)
        PVAL2   *realptr;                       // real ptr to ver2.5 PVAL

バージョンチェックのためのフィールドです(PVAL構造体のみ)。 versionには、HSPのバージョンコードがセットされます。(ver2.5ならば0x0205です)

もし、ver2.5以前のHSPであれば、versionは0になっています。 realptrは、もしver2.5以上の場合には、実際のPVAL2構造体へのポインタが収められています。

これらのフィールドは、PVALとPVAL2の両方に対応したDLLを作成する場合に使用されるものです。

まず、versionフィールドをチェックして、0でなければ realptrのポインタを、 PVAL2へのポインタとして処理を行なうことで、ver2.4g以降すべてのHSPで動作する命令となります。 (これはサンプルDLLのautochkで行なっているので参考にしてみてください)

BMSCR構造体の詳細

BMSCR構造体はhspdll.hで以下のように定義されています。 なるべく互換性を保つようにしたいと思っていますが、 将来HSPのバージョン アップでBMSCR構造体が変更される可能性はあります。

#define objkazz 64
typedef struct BMSCR
{
        //              Bitmap buffer structure
        //
        int             flag;                   // used flag
        int             sx;                     // X-size
        int             sy;                     // Y-size
        int             palmode;                // palmode
        HDC             hdc;                    // buffer HDC
        BYTE    *pBit;                          // bitmap pointer
        BITMAPINFOHEADER *pbi;                  // infoheader
        HBITMAP dib;                            // bitmap handle(DIB)
        HBITMAP old;                            // bitmap handle(OLD)
        RGBQUAD *pal;                           // palette table
        HPALETTE hpal;                          // palette handle
        HPALETTE holdpal;                       // palette handle (old)
        int             pals;                   // palette entries
        HWND    hwnd;                           // window handle
        HANDLE  hInst;                          // Instance of program
        int             infsize;                // *pbi alloc memory size
        int             bmpsize;                // *pBit alloc memory size

        //              Window object setting
        //
        int             type;                   // setting type
        int             wid;                    // window ID
        short   fl_dispw;                       // display window flag
        short   fl_udraw;                       // update draw window
        int             wx,wy,wchg;             // actual window size x,y
        int             xx,yy;                  // buffer view point x,y
        int             lx,ly;                  // buffer view size x,y
        int             cx,cy;                  // object cursor x,y
        int             ox,oy,py;               // object size x,y,py
        int             texty;                  // text Y-axis size
        int             gx,gy,gmode;            // gcopy size

        HBRUSH  hbr;                            // BRUSH handle
        HPEN    hpn;                            // PEN handle
        HFONT   hfont;                          // FONT handle
        HFONT   holdfon;                        // FONT handle (old)
        COLORREF color;                         // text color code

        HANDLE  hCld[objkazz];                  // buttonのhandle
        int             owid[objkazz];          // buttonのjump ID
        int             owb;                    // handleのindex

        int             textspeed;              // slow text speed
        int             cx2,cy2;                // slow text cursor x,y
        int             tex,tey;                // slow text limit x,y
        char    *prtmes;                        // slow message ptr

} BMSCR;

それぞれのメンバには、HSPが管理するウインドゥ画面についての情報が格納されています。 DLLに、BMSCR構造体へのポインタが渡される場合は、 現在の操作先画面(gsel命令で指定したウインドゥID)の情報が渡されます。

それぞれのメンバの詳細は以下の通りです。

        int             flag;                   // used flag

BMSCRが管理する画面が使用されているかどうかのフラグです。 TRUEなら初期化済み、FALSEなら初期化されていません。

        int             sx;                     // X-size
        int             sy;                     // Y-size
        int             palmode;                // palmode

画面を初期化したサイズが格納されています。 sx,syはX,Y方向のドット数になります。 palmodeは1ならパレットモード、0ならフルカラーモードです。

        HDC             hdc;                    // buffer HDC

画面のデバイスコンテキストが格納されています。 このハンドルを使ってGDIファンクションで画面に描画することが可能です。

注意しなければならないのは、これはメモリ上のビットマップへのデバイスコンテキストだということです。 ここに描画をしても、実際のウインドゥ画面上では何の変化も起こりません。

実際のウインドゥ画面に変更を反映させるためには、 HSPのredraw命令などを使用して再描画を行なうか、 GetDC命令で実際のウインドゥへのデバイスコンテキストを取得して描画する必要があります。

        BYTE    *pBit;                          // bitmap pointer

画面のビットマップデータが格納されているメモリの先頭アドレスです。 このポインタを使って直接、画面にデータを書き込むことが可能です。

メモリにデータを直接書き込み場合は、 色々な注意が必要です。詳しくは、 「ビットマップ画面への直接書き込み」を参照してください。

        BITMAPINFOHEADER *pbi;          // infoheader
        HBITMAP dib;                            // bitmap handle(DIB)
        HBITMAP old;                            // bitmap handle(OLD)

画面データを管理するビットマップについての情報です。 oldメンバは、ワークに使用しているだけなので特に決まった値は格納され ません。

        RGBQUAD *pal;                           // palette table
        HPALETTE hpal;                          // palette handle
        HPALETTE holdpal;                       // palette handle (old)
        int             pals;                   // palette entries

画面に適用されているパレットの情報です。 holdpalメンバは、ワークに使用しているだけなので特に決まった値は格納されません。 パレットの変更はなるべくHSP側の命令で行なうようにして、 このメンバは参照だけにとどめておいてください。

        HWND    hwnd;                           // window handle

画面の描画先にあたるウインドゥのハンドルです。

        HANDLE  hInst;                          // Instance of program

ウインドゥを管理するプログラムためのインスタンスです。

        int             infsize;                // *pbi alloc memory size
        int             bmpsize;                // *pBit alloc memory size

画面データ初期化時のメモリ使用量を示すワークです。

        int             type;                   // setting type

画面の属性を示します。 数値の示す内容は以下の通りです。

type :

1 off screen buffer
2 background image (full size)
3 hsp main window (fixed size)
4 normal window (fixed size)
5 picture window (flex size)
6 special window (stretch)
7 screen saver preview window
        int             wid;                    // window ID

ウインドゥIDを示します。

        short   fl_dispw;                       // display window flag
        short   fl_udraw;                       // update draw window
}}

画面がウインドゥとして表示されているかどうか、 画面の更新が必要かどうかを示すフラグです。

{{{
        int             wx,wy,wchg;             // actual window size x,y
        int             xx,yy;                  // buffer view point x,y
        int             lx,ly;                  // buffer view size x,y

スクロールバーによってスクロールが可能なウインドゥでの、 表示ウインドゥサイズ、画面内から転送する元座標、転送する範囲 などを示します。

        int             cx,cy;                  // object cursor x,y

カレントポジションを示します。

        int             ox,oy,py;               // object size x,y,py

objsize命令で指定したオブジェクトの大きさを示します。 pyメンバは、カレントポジションをY方向へ増加する際のドット数になり ます。

        int             texty;                  // text Y-axis size

現在選択されている文字フォントのY方向のサイズを示します。

        int             gx,gy,gmode;            // gcopy size

gmode命令で指定した画面コピー時のサイズとモードを示します。

        HBRUSH  hbr;                            // BRUSH handle
        HPEN    hpn;                            // PEN handle

color命令で指定した色によるブラシとペンを示すオブジェクトの ハンドルです。

        HFONT   hfont;                          // FONT handle
        HFONT   holdfon;                        // FONT handle (old)

font命令で指定したフォントのオブジェクトハンドルです。 holdfonはワーク用で特に決まった値は持ちません。

        COLORREF color;                 // text color code

color命令で指定した色データを示します。

        HANDLE  hCld[objkazz];                  // buttonのhandle
        int             owid[objkazz];          // buttonのjump ID
        int             owb;                    // handleのindex

画面上に配置するHSPのオブジェクト(ボタンや入力ボックスなど) に関する情報が格納されています。 hCld[n]はオブジェクトハンドル、 owid[n]は各種情報を示しています。(nはオブジェクトID)

また、owbは現在表示されているオブジェクトの個数を示しています。 objkazzは64と定義され、最大64個のHSPオブジェクトを画面に配置 することができます。

        int             textspeed;              // slow text speed

text命令で指定したテキストの表示スピードを示します。

        int             cx2,cy2;                // slow text cursor x,y
        int             tex,tey;                // slow text limit x,y
        char    *prtmes;                        // slow message ptr

ゆっくりと文字列を表示するためのワークです。

ビットマップ画面への直接書き込み

BMSCR構造体のpBitメンバには、画面のビットマップデータが格納されているメモリの先頭アドレスが格納されています。 これを使って直接、画面にデータを書き込むことが可能です。

直接メモリをアクセスすることで、GDIを使った時よりも数倍速い処理が可能になります。 また、画面のドット単位に自由にアクセスできるので特殊効果や画像の変換などにも非常に便利てす。

ただし、これには注意しなければならない点がいくつかあります。

画面とメモリアドレスの対応が上下逆になっています

Windowsのビットマップ管理は、なぜか一番下のラインから順に上に上がっていく構造になっています。 この不思議な構造のせいで、いままで画面の左上から下に向かって進む構造に慣れていた人は苦しむかもしれません。

たとえば、画面のサイズが640x480で(0,0)-(639,479)の範囲がメモリ上にあるとすれば、pBitが示す先頭メモリは(0,479)の座標(左下)にあたります。

そこから、X方向(右)にアドレスが増加していきますが、(639,479)まで進んで 次は、(0,478)になります。 そして再び、(639,478)まで進んで、その次は (0,477)となります。これを(639,0)まで繰り返す形でドットのデータが並んで います。

ドットのデータは画面の色数(palmodeメンバ)によって異なります。 フルカラーモードの場合は、1ドット3バイト(24bit)で「B,G,R,B,G,R...」 の順番に各色の輝度を示します。また、パレットモードの場合は、 1ドット1バイト(8bit)でパレットコードを示しています。

画面の範囲外にあたるメモリに書き込むと一般保護違反が出て止まります

ビットマップ画面は、単なるメモリ上の空間に過ぎません。ここの、 範囲外にデータを書き込むとWindowsのエラーとなりHSPが一般保護違反で終了します。 画面の範囲は、sx,syメンバで知ることができます。これをもとに範囲から出ないように気をつけてください。

画面上の任意の点X,Yを示すアドレスは以下の式で求められます。

(パレットモード(256色)時)

              x = X座標;
              y = Y座標;
              vram_adr = pBit + ( ( sy - 1 - y ) * sx ) + x;

(フルカラーモード(1670万色)時)

              x = X座標;
              y = Y座標;
              vram_adr = pBit + ( ( sy - 1 - y ) * sx * 3 ) + ( x * 3 );

ビットマップを書き換えた後は、実際の画面の更新をする必要があります

これは、hdcメンバを使用してGDIファンクションによる描画をした時にも言えることですが、 メモリ上のビットマップに描画をしても、実際のウインドゥ画面上では何の変化も起こりません。

メモリ上の画面と、実際の画面上のウインドゥ内は別です。メモリ上の画面を更新した後は、 実際の画面上のウインドゥにその内容をコピーして更新しなければなりません。

変更を反映させる最も簡単な方法は、HSPのredraw命令を使用して再描画を行なうことです。 これは、全画面を更新して書き換えるので、ひととおりメモリ上の画面を書き換え終わってから 一気にredraw命令で更新した方が効率的です。この方法でも、GDIに比べれば十分に高速になります。

もう1つの方法は、hwndメンバを使ってGetDC命令で実際のウインドゥへのデバイスコンテキストを取得して、 自分で更新するというものです。

この方法については、「HSPサポートルーチンズ」でサポートされている関数を使用することで比較的容易に行なえます。 詳しくは、hspsdkディレクトリのhspsdk.cppソースファイルをご覧下さい。

最後に

まだ解説が足りない部分もあるかと思いますが、 これでかなりの拡張を HSPに行なうことが可能になると思います。

その気になれば、Cではなくてインラインアセンブラを使ってマシンコードを書けば、 すごいパフォーマンス も夢ではないかも…。これを読んでステキなHSPのDLLを作ってくれると嬉しいです。(おにたま)