loadlib関連命令とllmodモジュール
まずは、loadlib関連命令とllmodモジュールで使われる命令群を簡単に説明しておきましょう。
loadlib関連命令
loadlib関連命令(あるいはloadlib系命令、loadlib命令群などとも呼ばれる)とは、HSP 2.6以降で標準で提供されているいくつかの命令のことで、Win32 APIやその他のDLL関数を呼び出すために必要な機能を提供しています。以前のバージョンのHSP(HSP 2.55以前)では、これらの命令はtomさんによって開発・公開されていた拡張プラグインloadlib.dllで提供されていたものでした。しかし、Win32 APIがHSPで広く使われるようになってきたため、これらの命令が標準命令として実装されたのです。
loadlib関連命令は、主に次のような機能を提供しています。
- メモリアクセス機能
- HSPで使われている変数を指すメモリアドレスを取得する。
- 任意のメモリアドレスへデータを読み書きする。
- DLL関数呼び出し機能
- Windowsから提供されているWin32 APIを呼び出す。
- 他のDLLに実装されている関数を呼び出す。
メモリアクセス機能
loadlib関連命令として提供されている命令のうち、メモリアクセス操作をするものです。
- ll_getptr v1
- 変数v1のメモリアドレス取得
アドレスはあらかじめll_retsetで指定されていた変数(llmodモジュールを使っている場合は変数dllret)に格納される。また、ll_ret命令で取得することもできる。
- ll_peek v1, n2, n3
- 任意のメモリアドレスn2からn3バイトのデータまたは文字列を読み込み変数v1に格納
n3を省略した場合は文字列とみなされる。
- ll_peek1 v1, n2
- 任意のメモリアドレスn2から1バイトを読み込み変数v1に格納
- ll_peek2 v1, n2
- 任意のメモリアドレスn2から2バイトを読み込み変数v1に格納
- ll_peek4 v1, n2
- 任意のメモリアドレスn2から4バイトを読み込み変数v1に格納
- ll_poke v1, n2, n3
- 任意のメモリアドレスn2へ変数v1に格納されているデータn3バイトまたは文字列を書きこみ
n3を省略した場合は文字列とみなされる。
- ll_poke1 n1, n2
- 任意のメモリアドレスn2へ1バイト数値データn1を書きこみ
- ll_poke2 n1, n2
- 任意のメモリアドレスn2へ2バイト数値データn1を書きこみ
- ll_poke4 n1, n2
- 任意のメモリアドレスn2へ4バイト数値データn1を書きこみ
詳しい使用方法はHSPに添付されているヘルプやサンプルプログラムを参照してください。
DLL呼び出し機能
loadlib関連命令を用いてDLL関数を呼び出すには2種類の方法があり、それによって、使う命令が異なってきます。
- タイプA
この方法でDLL関数を呼び出す場合、プログラマはDLLのハンドルというものを意識する必要がありません。また、関数を呼び出す際(ll_callを実行するとき)にDLLをメモリ上にロードする仕組みになっているため、関数実行後に常にDLLを解放するように心がければメモリを節約することにつながると思われます。(システムDLLの場合は常にメモリ上に存在するのであまり関係ないかもしれませんが。)
- ll_dll s1
- 呼び出す関数が含まれているDLLファイル名を設定
- ll_func s1
- 呼び出す関数名を設定
- ll_type s1, n2
- 引数の型を設定
- ll_n n1, n2
- 数値引数の設定
- ll_s s1, n2
- 文字列引数の設定
- ll_z s1, n2
- 文字列引数の設定(DLL側でメモリを確保)
- ll_p v1, n2
- ポインタ引数の設定
- ll_call
- DLLのロード、関数呼び出し
- ll_ret v1
- 直前に呼び出した関数の戻り値を取得して変数v1に格納
- ll_retset v1
- 関数呼び出し時に変数v1に自動的に戻り値が格納されるように設定
- ll_free
- DLLの解放
- タイプB
この方法は、C言語などでDLLを動的にロードする場合とほぼ同じ手順で行なうものです。DLLのハンドルを意識する必要があります。また、DLLをロードしてから解放するまでの間、DLLのコードがメモリ内に読み込まれた状態になります。したがって、関数1つを呼び出すたびにDLLをロードするということはしません。
一般的な使用ではこちらの方をお勧めします。
- ll_libload v1, s2
- ファイル名s2のDLLをロードし、ハンドルをv1に格納
- ll_libfree n1
- ハンドルn1のDLLを解放
- ll_getproc v1, s2, n3
- ハンドルn3のDLLに含まれる関数名s2の関数のポインタを取得して変数v1に格納
- ll_callfunc v1, n2, n3
- 配列変数v1に格納されているn2個の引数を渡して関数ポインタn3の関数の呼び出し
- ll_callfnv n1
- 引数を持たない関数ポインタn3の関数の呼び出し
- ll_ret v1
- 直前に呼び出した関数の戻り値を取得して変数v1に格納
- ll_retset v1
- 関数呼び出し時に変数v1に自動的に戻り値が格納されるように設定
このページではllmodモジュールを中心としてAPI関数呼び出しを行なっていくのですが、こちらはタイプBの方と大いに関連があります。そのため、このページではタイプAの方法については説明せずに、タイプBの方法のみ説明していくことにします。
llmodモジュール
llmodモジュールは、loadlib関連命令の機能をより簡単に使うことができるように、基本的な機能やよく使われる関数をモジュール命令として定義したものです。llmodモジュールは以下の機能を提供しています。
- 変数のアドレス取得の簡略化
- 関数の戻り値を入れる変数をdllretに設定
- 関数呼び出しの簡略化
- 基本的なシステムDLLのロード
- その他の基本的なWin32 API関数の呼び出し
llmodモジュールの中で定義されるの重要な命令は以下の2つです。
getptr命令
- getptr v1, v2
-
v1:取得したアドレスを格納する数値変数
v2:メモリアドレスを取得する変数
変数のメモリアドレスを取得するにはgetptr命令を使います。数値変数や文字列変数、また、それらの配列変数の要素に対しても使うことができます。Win32 API関数の引数としてメモリアドレスが必要な場合には、通常、この命令で取得したアドレスを指定します。ちなみに、
getptr v1, v2
の代わりに、
ll_getptr v2 : ll_ret v1
としても同じことができます(llmodモジュールを使わない場合などに用いられます)。
dllproc命令
- dllproc s1, v2, n3, n4
-
s1:関数名
v2:関数に渡す引数の入った数値配列変数
n3:引数の数
n4:DLLのハンドル
dllproc命令は、Win32 API関数を呼び出すための命令です。この命令の詳しい使い方は後で述べることにします。
その他のモジュール命令群
LLMODには他にもいくつかの命令が定義されています。主なモジュール命令を以下に示します。(内部で使用していると思われるモジュールも一部示しておきます。)
- dll_getfunc v1, s2, n3
- 関数のアドレスを取得(あらかじめロードされているDLLに対しても有効)
- dll_getfunc v1, s2, n3
- 関数のアドレスを取得(あらかじめロードされているDLLに対しても有効)
- getmjrdll v1, n2
- あらかじめロードされているDLLのハンドルを取得
- _get_instance v1
- HSPのインスタンスハンドル取得
- _get_active_window v1
- 現在アクティブなHSPウィンドウのハンドル取得(GetActiveWindow関数)
- sendmsg v1
- ウィンドウにメッセージを送信(SendMessage関数)
- setwndlong v1, n2
- SetWindowLong関数(n2がゼロのとき)またはGetWindowLong関数(n2がゼロ以外のとき)
- _null_sep_str v1, n2
- 変数v1に格納されている文字列の文字コードn2の文字をヌル文字に置き換える(ヌル文字区切りの文字列を作成)
- _makewnd v1, s2
- ウィンドウの作成(CreateWindowEx関数)
- _is_wnd n1
- 指定したハンドルのウィンドウが存在するか調べる。(IsWindow関数)
- _hspobjhandle n1
- オブジェクトIDのHSPオブジェクトのウィンドウハンドルを取得しstatに格納
- _hspobjid n1
- ウィンドウハンドルからHSPオブジェクトIDを調べstatに格納
- _objsel n1
- オブジェクトIDn1のHSPオブジェクトにキー入力フォーカス設定
n1にウィンドウハンドルを指定することも可能。n1に-1を指定するとフォーカスを持つHSPオブジェクトのIDまたはウィンドウのハンドルをstatに格納する。
- charupper v1
- 変数v1に格納されている文字列の英字を大文字に変換(CharUpper関数)
- charlower v1
- 変数v1に格納されている文字列の英字を小文字に変換(CharLower関数)