*********************************************************************** LoadLib ver 1.10 HSP2で他のDLLの関数を使うことができるようにするプラグイン 2001 8 7 tom *********************************************************************** ●説明 loadlib命令群は、WindowsのDLLファイルを自由に呼び出すための命令セットです。 この命令群を使用すればHSPでHSPプラグイン以外のDLLの関数を使うことが できるようになります。 HSP標準でサポートしてないWin32APIなどを使うとき少し役に立ちます。 他のDLLの関数を使うだけのDLLを作るのが面倒という人におすすめです。 ●ファイル詳細 _CallFunc.asm loadlib.dllのソース(LCCWIN32用) _CF_MASM.asm loadlib.dllのソース(MASM用) loadlib.as loadlib.dllを使うときにincludeするヘッダファイル loadlib.c loadlib.dllのソース loadlib.dll プラグイン本体 makefile LCCWIN32のMAKEFILE test_libload1.as サンプル test_libload2.as サンプル test_libload3.as サンプル test_libload4.as サンプル test_libload5.as サンプル test_libload6.as サンプル test_libload7.as サンプル ●使い方 命令を使用する手順は 0. #include "loadlib.as"でloadlib.asをインクルードする。 1. ll_dllでDLLの名前をセットする。 2. ll_funcで関数の名前をセットする。 3. ll_typeで関数の引数のタイプをセットする。 4. ll_n,ll_s,ll_z,ll_pで引数をセットする。(引数がない場合はセットしない) 5. ll_callでDLLのロード、関数呼び出し。 6. もしDLLを使わなくなったらll_freeでDLLの開放。 または 0. #include "loadlib.as"でloadlib.asをインクルードする。 1. ll_libloadでDLLをロードする。 2. ll_getprocでDLL内の関数のアドレスを取得する。 3. ll_callfuncで関数を呼び出す。 4. もしDLLを使わなくなったらll_libfreeでDLLの開放。 という具合です。 あとはサンプルを実行してみてください。 ●その他 LoadLibを使用したソフトの配布なども自由にしてもらって構いません。 ソースも自由に使ってください。 但し、LoadLibを使って何らかの被害を受けたとしても、 作者は一切の責任を負いません。 e_mail : takano@mxj.mesh.ne.jp ・loadlib.dll配布場所 http://www5b.biglobe.ne.jp/~diamond/hsp/hsp2file.htm ●変更履歴 1.10 ll_bin、ll_str命令を追加しました。 1.05 HSP ver 2.55で実行するとエラーが出たサンプルを修正。 それ以外は全く変わっていません。 1.04b->1.04c WindowsNTで動作しないとのご報告を頂いたので修正しました。 それ以外は全く変わっていません。 1.04 hsファイルを添付した。 バージョンリソースを付けた。 ●loadlib.dll各命令の説明 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ●dllの名前を設定 ll_dll "s1" s1 : DLLの名前が入った文字列変数、又は文字列 <>説明 使用するDLLの名前を設定します。この時点ではまだDLLはロードされません。 DLLの名前を設定すると、以前にロードされていたDLLがあった場合、 以前のDLLは開放されます。 ※ll_dllを使うとll_n, ll_s, ll_z, ll_pでセットした値は全てリセットされます <>例 dll = "user32.dll" ll_dll dll ll_dll "kernel32.dll" <>参照 ll_type ll_func ll_n ll_s ll_z ll_p ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ●関数名を設定 ll_func "s1" s1 : 関数名が入った文字列変数、又は文字列 <>説明 関数名を設定します。ll_call命令を使うとここで設定した関数が呼び出されます。 ウィンドウズAPIの関数名は、文字列にUnicodeを使うタイプは'W'、そうでないとき (ANSIタイプ)は'A'が付くものが多いので注意してください。 ('W'も'A'も付かないものもあります。) ※ll_funcを使うとll_n, ll_s, ll_z, ll_pでセットした値は全てリセットされます <>例 func = "WinHelpA" ll_func func ll_func "MessageBoxA" <>参照 ll_dll ll_type ll_n ll_s ll_z ll_p ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ●引数のタイプを設定(小文字でも大文字でも良い) ll_type "s1",n2 s1 : 引数のタイプを示した文字列変数、又は文字列 n2 : HSP用プラグインを使うときのオプション <>説明 ll_funcで設定する関数の引数のタイプを設定します。 引数のタイプは以下の通りです。 N:数値型,またはll_retで取得した返り値を使うとき S(Z):文字列型 P:ポインタ型 V:引数無し A:これ以降の引数のタイプをチェックしない Aはsprintfなどの引数の数が決まっていないときに使ってください。 大文字小文字は関係ありません。 見やすくするためにスペースを途中に入れることもできます。 それ以外の文字はll_call使用時にエラーになります。 ※ll_typeを使うとll_n, ll_s, ll_z, ll_pでセットした値は全てリセットされます n2はll_dll,ll_func,ll_type,ll_callなどでHSP用プラグインを使うときの オプションです。 HSP用のプラグインの引数には特殊な値が使われることもあるため、 そのままではloadlib.dllで使えないこともあります。また、関数名も _***@16の様に書かなければならず、見た目もよくありません。 このオプションはこれを解消するためのものです。 ここには各プラグインのヘッダーで書かれている数値を入れます。 例えばヘッダーに #func ll_z ll_z 6 ;関数のタイプは6 と書いてあった場合、 ll_func "ll_z" ;オプションを付けないときは ll_func "_ll_z@16" ll_type "Z",6 ;オプションを付けないときは ll_type "PZ" ll_z "test" ;オプションを付けないときは ll_p bmscr : ll_z "test" ll_call という感じになります。 ただし、関数のタイプが0の場合は、p2は0x100($100)にして下さい。 <>例 type = "SSNP" ; 0番目の引数は文字列型, 1番目の引数も文字列型, ; 2番目の引数は数値型, 3番目の引数はポインタ型 ll_type type type = "V" ; 引数無し ll_type type ll_type "psa" ; 0番目の引数はポインタ型, 1番目の引数は文字列型, ; 2番目以降の引数のタイプはチェックしない <>参照 ll_dll ll_func ll_ret ll_n ll_s ll_z ll_p ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ●数値引数の設定 ll_n n1,n2 n1 : 数値又は数値変数 n2 : n1が何番目の引数かを表す数字(初めの引数を0番目とする) <>説明 数値型の引数を設定します。関数呼び出しの際にn2番目の引数にn1の値が使われます。 n2には初めの引数を0番目と数えて数値を入れてください。 n2を省略(0を代入)すると、n1は以前に設定した引数の次の引数として扱われます。 n2に-1を代入すると、再び0番目からの入力になります。 ll_func,ll_type命令を使うと、以前に設定した引数は全てリセットされ、 n2を省略したときの値は0からになります。 <>例 type = "NNN" ll_type type num = 999 ll_n 27 ;0番目の引数を27にセット ll_n num ;1番目の引数をnumの値(999)にセット ll_n 100 ;2番目の引数を100にセット ll_call ll_n 50,1 ;1番目の引数を50に替える ll_n 150 ;2番目の引数を150にセット ll_call ll_n 4,-1 ;再び0番目から引数をセット(4は0番目の引数) ll_n 55 ;1番目の引数を55にセット . . x1 = 1024 : x2 = $50 type = "NNNN" ll_type type ;ll_type命令を使うとp2を省略したときの値が0に戻る ll_n x1 ;0番目の引数をx1の値にセット ll_n x2 ;1番目の引数をx2の値にセット . . <>参照 ll_func ll_type ll_s ll_z ll_p ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ●文字列引数の設定 ll_s s1,n2 s1 : 文字列変数 n2 : s1が何番目の引数かを表す数字(初めの引数を0番目とする) <>説明 文字列型の引数を設定します。関数呼び出しの際にn2番目の引数にs1に代入され ている文字列へのポインタが使われます。 引数に文字列へのポインタを使いたいときにこの命令を使います。 n2についてはll_nと同様です。 ll_func,ll_type命令を使うと、以前に設定した引数は全てリセットされます。 ※この命令は引数に文字列へのポインタを使うということを明示して使うために あります。引数のタイプをポインタ型(P)にして、この命令を次のll_pに置き換え ても構いません。 <>例 type = "SN" ll_type type char = "abcdefg" ll_s char ll_n 7 <>参照 ll_func ll_type ll_n ll_z ll_p ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ●文字列引数の設定(2) ll_z n1,n2 n1 : 文字列変数は文字列 n2 : n1が何番目の引数かを表す数字(初めの引数を0番目とする) <>説明 文字列型の引数を設定します。関数呼び出しの際にn2番目の引数にn1に代入され ている文字列へのポインタが使われます。 引数に文字列へのポインタを使いたいときにこの命令を使います。 ll_zはll_sと違いメモリを新たに確保し、それに文字列をコピーしたものを使い ます。(ll_sは変数のポインタを使うので新たにメモリは確保しません。) n2についてはll_nと同様です。 ll_func,ll_type命令を使うと、以前に設定した引数は全てリセットされます。 <>例 type = "ZN" ;"SN"でもOK ll_type type ll_z "abcdefg" ll_n 7 <>参照 ll_func ll_type ll_n ll_s ll_p ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ●ポインタ引数の設定 ll_p v1,n2 v1 : 変数 n2 : v1が何番目の引数かを表す数字(初めの引数を0番目とする) <>説明 ポインタ型の引数を設定します。関数呼び出しの際にn2番目の引数にv1に指定した 変数へのポインタが使われます。 引数にバッファへのポインタを使いたいときなどに使います。 NULLを使いたいときは、引数のタイプを数値型にして引数に0を代入してく ださい。n2についてはll_nと同様です。 ll_func,ll_type命令を使うと、以前に設定した引数は全てリセットされます。 <>例 mybuffer = "" dll = "msvcrt.dll" : ll_dll dll func = "_itoa" : ll_func func type = "NPN" : ll_type type ll_n 100 ll_p mybuffer ;引数に変数mybufferへのポインタを使う ll_n 16 ll_call dialog "mybuffer="+mybuffer <>参照 ll_func ll_type ll_n ll_s ll_z ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ●DLLのロード、関数呼び出し ll_call <>説明 ll_dllでセットしたDLLをロードし、ll_funcで設定した関数呼び出します。 ll_call命令を使った後、システム変数statに以下の値がセットされます。 ll_funcで設定した関数の返り値は、ll_retで取得できます。 システム変数statの値 0 : エラーが起きなかったとき。 1 : ll_typeでセットした型とll_n,ll_s,ll_z,ll_pでセットした型があっていないとき。 2 : ll_dllでセットしたDLLが使えないとき。(LoadLibraryが失敗したとき。) 3 : ll_funcで設定した関数が使えないとき。(GetProcAddressが失敗したとき。) また、この関数を使うと dll名/関数名/関数タイプ/$HSP用プラグインの関数タイプ(16進) の形式でシステム変数refstrに文字列がコピーされます。 <>参照 ll_dll ll_func ll_type ll_free ll_ret ll_n ll_s ll_z ll_p ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ●DLLの開放 ll_free <>説明 ll_callでロードされたDLLを開放します。 プログラム中でロードしたDLLが必要なくなったときこの命令を使います。 この関数はプログラム終了時にHSPから自動的に呼び出されるので、 プログラムが終了してしまうときにはこの関数を使わなくても大丈夫です。 DLLがロードされていないときにll_freeを使っても害はありません。 <>参照 ll_call ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ●呼び出した関数の返り値を取得 ll_ret v1 v1 : 関数の返り値を取得を取得する数値型変数 <>説明 ll_funcで設定した関数をll_callで呼んだ後、その関数の返り値を取得する ときにこの命令を使います。 v1には必ず数値型変数を使ってください。v1に文字列変数を使った場合 システム変数statに1が代入され、関数の返り値は取得できません。 ll_retで取得した返り値を他の関数で使うときは、数値型(N)として使って ください。 <>例 ll_dll "user32.dll" ll_type "v" ll_func "GetActiveWindow" ll_call ll_ret hWnd ;変数hWndに関数の返り値代入する。 <>参照 ll_call ll_callfunc ll_callfn ll_retset ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ●変数のポインタを取得 ll_getptr v1 v1 : 変数 <>説明 変数v1のポインタを知りたいときに使います。 ll_retでv1のポインタを取得できます。 <>例 ll_getptr sample ll_ret p_sample ;変数sampleのポインタをp_sampleに代入する。 <>参照 ll_ret ll_retset ll_peek ll_peek1 ll_peek2 ll_peek4 ll_poke ll_poke1 ll_poke2 ll_poke4 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ●ポインタを使った読み込み ll_peek v1,n2,n3 v1 : 読み込み先の変数 n2 : ポインタ n3 : 読み込むバイト数 <>説明 n2で指定したポインタから変数v1へn3バイト読み込みます。 n3を省略(0を代入)するとn2を文字列のポインタとみなし、 文字列全てを読み込みます。 <>例 ll_peek y,p_x,4 ;ポインタp_xから変数yに4バイト読み込む <>参照 ll_getptr ll_ret ll_retset ll_peek1 ll_peek2 ll_peek4 ll_poke ll_poke1 ll_poke2 ll_poke4 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ●ポインタを使った1バイトの読み込み ll_peek1 v1,n2 v1 : 読み込み先の変数 n2 : ポインタ <>説明 n2に指定したポインタから変数v1へ1バイト読み込みます。 <>参照 ll_getptr ll_peek ll_peek2 ll_peek4 ll_poke ll_poke1 ll_poke2 ll_poke4 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ●ポインタを使った2バイトの読み込み ll_peek2 v1,n2 v1 : 読み込み先の変数 n2 : ポインタ <>説明 n2に指定したポインタから変数v1へ2バイト読み込みます。 <>参照 ll_peek ll_peek1 ll_peek4 ll_poke ll_poke1 ll_poke2 ll_poke4 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ●ポインタを使った4バイトの読み込み ll_peek4 v1,n2 v1 : 読み込み先の変数 n2 : ポインタ <>説明 n2に指定したポインタから変数v1へ4バイト読み込みます。 <>参照 ll_peek ll_peek1 ll_peek2 ll_poke ll_poke1 ll_poke2 ll_poke4 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ●ポインタを使った書き込み ll_poke v1,n2,n3 v1 : 書き込む内容が入っている変数 n2 : ポインタ n3 : 書き込むバイト数 <>説明 n2で指定したポインタへ変数v1の内容をn3バイト書き込みます。 n3を省略(0を代入)するとv1を文字列変数とみなし、 文字列全てを書き込みます。 <>例 ll_poke x,p_s,15 ;ポインタp_sに変数xの内容を15バイト書き込む <>参照 ll_peek ll_peek1 ll_peek2 ll_peek4 ll_poke1 ll_poke2 ll_poke4 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ●ポインタを使った1バイトの書き込み ll_poke1 n1,n2 n1 : 書き込む数値[0〜0xff] n2 : ポインタ <>説明 n2で指定したポインタへn1で指定した値を1バイト書き込みます。 <>例 ll_poke1 0xfc,p <>参照 ll_peek ll_peek1 ll_peek2 ll_peek4 ll_poke ll_poke2 ll_poke4 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ●ポインタを使った2バイトの書き込み ll_poke2 n1,n2,n3 n1 : 書き込む数値[0〜0xffff] n2 : ポインタ n3 : オプション <>説明 n2で指定したポインタへn1で指定した値を2バイト書き込みます。 普通は0x11FFはメモリに FF 11 と書き込まれますが、(Little Endianの場合) オプションを0以外の値にすると11 FF と書き込みます。 <>例 ll_poke2 0x1010,p <>参照 ll_peek ll_peek1 ll_peek2 ll_peek4 ll_poke ll_poke1 ll_poke4 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ●ポインタを使った4バイトの書き込み ll_poke4 n1,n2,n3 n1 : 書き込む数値[0〜0xffffffff] n2 : ポインタ n3 : オプション <>説明 n2で指定したポインタへn1で指定した値を4バイト書き込みます。 普通は0x11FF22CCはメモリに CC 22 FF 11 と書き込まれますが、(Little Endianの場合) オプションを0以外の値にすると 11 FF 22 CC と書き込みます。 <>例 ll_poke4 0x1010ffcc,p <>参照 ll_peek ll_peek1 ll_peek2 ll_peek4 ll_poke ll_poke1 ll_poke2 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ●DLLのロード ll_libload v1,"s2" v1 : DLLのハンドルを受けるための変数 s2 : DLLの名前が入った文字列変数又は文字列 <>説明 s2で指定したDLLをロードし、変数v1にDLLのハンドルを代入します。 (この命令はWin32APIのLoadLibraryそのものです。) <>例 ll_libload h_User32,"user32.dll" <>参照 ll_getproc ll_libfree ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ●DLLの開放 ll_libfree n1 n1 : ll_libloadで取得したDLLのハンドル <>説明 ll_libloadを使ってロードしたDLLを開放します。 必要がなくなったDLLはこの命令で開放してください。 (この命令はWin32APIのFreeLibraryそのものです。) <>例 ll_libload h_User32,"user32.dll" . . ll_libfree h_User32 <>参照 ll_libload ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ●DLL内の関数のポインタを取得 ll_getproc v1,"s2",n3 v1 : 関数のポインタを受けるための変数 s2 : 文字列又は文字列変数 n3 : ll_libloadで取得したDLLのハンドル <>説明 ll_libloadで取得したDLLから関数s2のポインタを取得し、 変数v1に取得したポインタを代入します。 取得した関数のポインタはll_callfunc,ll_callfnvで使います。 (この命令はWin32APIのGetProcAddressそのものです。) <>例 ll_getproc p_MessageBox, "MessageBoxA", h_User32 <>参照 ll_libload ll_callfunc ll_callfnv ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ●引数が無い関数の呼び出し ll_callfnv n1 n1 : 関数のポインタ <>説明 n1で指定した関数を呼び出します。 n1にはll_getprocで取得した関数のポインタなどを使います。 関数の返り値はll_retを使って取得します。 <>例 ll_libload h_User32,"user32.dll" ll_getproc p_GetActiveWindow,"GetActiveWindow",h_User32 ll_callfnv p_GetActiveWindow ll_ret h_ActiveWnd ll_libfree h_User32 <>参照 ll_getproc ll_callfunc ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ●引数がある関数の呼び出し ll_callfunc v1,n2,n3 v1 : 引数が入った配列変数 n2 : 引数の数 n3 : 関数のポインタ <>説明 v1で指定した引数をn2個使い、n3で指定した関数を呼び出します。 n3にはll_getprocで取得した関数のポインタなどを使います。 関数の返り値はll_retを使って取得します。 <>例 msg = "message" : ll_getptr msg : ll_ret p_msg capt = "caption" : ll_getptr capt : ll_ret p_capt param.0=0 param.1=p_msg param.2=p_capt param.3=$21 param_n=4 ll_callfunc param, param_n, p_MessageBox ll_ret retMessageBox <>参照 ll_getproc ll_callfnv ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ●関数の返り値を入れる変数を指定 ll_retset v1 v1 : 関数の返り値を代入する変数 <>説明 ll_retsetを使用するとll_retで取得する値がv1に指定した変数に 代入されます。 <>例 ll_retset dllret msg = "message" : ll_getptr msg : p_msg=dllret capt = "caption" : ll_getptr capt : p_capt=dllret param.0=0 param.1=p_msg param.2=p_capt param.3=$21 param_n=4 ll_callfunc param, param_n, p_MessageBox retMessageBox=dllret <>参照 ll_ret ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ●16進文字列をバイナリに変換 ll_bin v1,"s2" v1 : バイナリに変換したものを代入する変数 s2 : バイナリに変換する文字列 <>説明 "01CDBF"などの16進文字列をバイナリに変換して、変数v1に代入します。 文字列の中に含まれるタブ、改行、スペースは無視されます (正確にはASCIIコード0x20以下の文字)。 0〜9、A〜F、a〜f以外の文字が現れた場合、変換はそこでストップされます。 変数v1に代入されたバイト数はll_retで取得できます。ll_retsetを使用している場合は ll_retsetでセットした変数に代入されます。 文字列全てが変換された場合はstatに0、途中でストップされた場合は statに1が代入されます。 v1のサイズが足りない場合も変換が途中でストップされ、statに2が代入されます。 <>例 sdim s, 256 alloc m, 256 s = {" 8B 44 24 04 ;mov eax,[esp+4] C1 E0 04 ;shl eax,4 C3 ;ret "} ll_retset ret ll_bin m, s if stat : dialog "エラー"+stat : end mes "変換されたバイト数 "+ret ll_getptr m prm = 1 ll_callfunc prm, 1, ret mes "ret="+ret stop <>参照 ll_ret ll_retset ll_str ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ●メモリの内容を16進文字列に変換 ll_str v1,n2,n3 v1 : 16進文字列に変換したものを代入する変数 n2 : 16進文字列に変換するメモリへのポインタ n3 : 変換するバイト数 <>説明 n2で指定したポインタ先のメモリの内容をn3バイトだけ16進文字列に変換します。 HSP標準命令のstrとは動作が違うので注意してください。 v1のサイズが足りない場合は変換が途中でストップされ、statに2が代入されます。 <>例 bin = $aaff3344, $55bb0011 ll_retset ret ll_getptr bin : pbin = ret ll_str s, pbin, 7 dialog s+"\nstat="+stat <>参照 ll_getptr ll_bin