WA_MACROを使ってみる ACT-1

HSP 2.6 のマクロ機能と WA_MACRO

拡張マクロ機能

HSP ver2.6からは、loadlib.dllの命令が標準命令として統合され、Win32 APIを使用したプログラムを公開する際にloadlib.dllをともに配布する必要がなくなって、HSPにおけるAPI関数の使い勝手がさらによくなりましたよね。

しかし、HSP ver2.6では、それ以外もいろいろな拡張がなされています。その1つに、#define 命令のマクロ機能の強化があります。以前のバージョンでは、#define 命令は単純に定数の置き換えを行なう機能しかありませんでしたが、新しいHSPでは、引数付きの展開を行なうことができるようになったのです。これにより、 #deffunc 命令でモジュール命令を定義するのと同じように、新しい命令を#define 命令で定義することもできるようになりました。この新しい命令では、複雑な展開の仕方を指定することもできるので、非常に便利なものとなっています。

WA_MACRO

現在では、HSP ver2.6用に公開されているモジュールなどには、新しいマクロ機能を使用したものが数多く存在します。そのうち、Win32 API関数の呼び出しのための機能を提供しているHSP ver2.61用マクロに、blueleafさんによって公開されている WA_MACRO があります。

WA_MACROは、これまでllmodモジュールによって実現できた機能を提供しており、さらに、Windowsの主要なシステムDLLが提供するAPI関数をマクロにより網羅しています。WA_MACROの優れている点は、llmodモジュールを使用する場合のような面倒な手続きが必要なく、API関数名と引数を指定するだけで関数の呼び出しができてしまうというところにあります。

では、API関数呼び出しがどれほど簡単になるかを見てみることにしましょう。例として、MessageBox 関数によるメッセージボックスの表示を行なってみるとします。まず、llmodモジュールを使用する場合には、次のようになりますね。

#include "llmod.as"

mref bmscr, 67           ; ウィンドウのBMSCR構造体を変数 bmscr に割り当てる
text1 = "LLMODを使ってます"
text2 = "API呼び出しテスト"

; MessageBox 関数の呼び出し
pm.0 = bmscr.13          ; ウィンドウハンドル
getptr pm.1, text1       ; 表示文字列へのポインタ
getptr pm.2, text2       ; キャプション文字列へのポインタ
pm.3 = 0x30              ; MB_OK | MB_ICONEXCLAMATION
dllproc "MessageBoxA", pm, 4, D_USER
end

一方、WA_MACRO を用いた場合には、次のように書くことができます。

#include "wam/user32.as"

; MessageBox 関数の呼び出し
MessageBox PRMHWND, SPTR("WA_MACROを使ってます"), SPTR("API呼び出しテスト"), 0x30
end

関数呼び出し部分が、たったの1行になってしまいました。llmodモジュールを使用した場合と比べると格段に簡単になってしまうことが分かりますね。

WA_MACROの使い方

では、WA_MACROを使用する方法を説明していくことにしましょう。最新のWA_MACROバージョン1.04はHSP 2.61が必須です。

WA_MACROのインストール

WA_MACROはblueleafさんのホームページにて公開されていますので、そこからダウンロードしましょう。現在の正式版の最新バージョンは1.04となっています。

blueleafさんのページ『青い葉っぱ』
http://hp.vector.co.jp/authors/VA034288/

WA_MACROのバージョン1.04をダウンロードしたら、ダウンロードしたアーカイブに含まれているwamフォルダを、HSPのcommonフォルダにコピーします(wamフォルダ内のファイルを個別にコピーするのではなく、wamフォルダそのものをcommonフォルダの中に入れてしまいましょう)。また、アーカイブ内にデバッグ実行時用のDLLが含まれているので、これをHSPがインストールされているフォルダにコピーします。他にも、helpフォルダの中にはマクロのヘルプが、omakeフォルダの中にはWin32 APIを使う上での便利なツールが含まれています。これらも、HSPがインストールされているフォルダの適当な場所にコピーしておきましょう。

WA_MACRO定義ファイル

WA_MACROでは、任意のDLLに含まれる任意の関数を呼び出したり、その関数を新しくマクロ定義したりすることができますが、とりあえずは、すでに提供されているシステムDLL関数用のマクロを使用していくことにしましょう。

WA_MACROでは、以下のファイルをインクルードすることで、それぞれのDLLが持っている関数を呼び出すことができるようになります。それぞれのファイル名の前に「wam/」をつける必要があることに注意してください。

winapi.as をインクルードすると、上のすべてのファイルで定義されるマクロをまとめて定義することできるようになっています。

さらに、以下のファイルも使うことができます。

もう一度言いますが、これらのファイル名の前には「wam/」を付けて指定しなければいけません。例えば、「wam/kernel32.as」や「wam/winapi.as」などのように指定します。

WM_MACROでAPI関数を呼び出してみる

では、実際にWM_MACROを使ってみることにしましょう。まずは、先ほどの MessageBox 関数の場合を例にとって説明していきます。

まず、マクロファイルのインクルードをする必要があります。MessageBox 関数はuser32.dll に含まれる関数であるので、「user32.as」をインクルードする必要があります(「winapi.as」でもいいですが)。「wam/user32.as」(または「wam/winapi.as」)と指定しなければいけません。

#include "wam/user32.as"

あとは、関数名を引数付きで記述すればOKです。

MessageBox PRMHWND, SPTR("WA_MACROを使ってます"), SPTR("API呼び出しテスト"), 0x30

MessageBox」と書けば、MessageBox 関数が呼び出されるようになっているわけです。非常に簡単ですね。文字列が関係するこの関数にはANSI文字列版の MessageBoxA とUnicode版の MessageBoxW がありますが、上のスクリプトのように最後の「A」を付けない形で指定すると MessageBoxA の方が呼び出されるようになっています。もちろん、

MessageBoxA PRMHWND, SPTR("WA_MACROを使ってます"), SPTR("API呼び出しテスト"), 0x30

のように明示的に「A」を付けた形で指定することも可能です。

さらに、それぞれのパラメータについて見ていくと、まず最初が「PRMHWND」となっていますね。これは関数呼び出し時のパラメータ用に定義されているマクロの1つで、描画中のウィンドウのウィンドウハンドルを渡すことができます。他にも、描画中のウィンドウとは別のウィンドウ、例えば、ウィンドウID2のウィンドウのハンドルを渡したい場合には、「PRMHWNDN(2)」と指定することができます。

次に、第2・3パラメータには、表示される文字列へのポインタ(アドレス)を渡さなければいけませんね。文字列へのポインタを渡すには、「SPTR」マクロを使って文字列を直接指定し、「SPTR("文字列")」のように記述します。ただし、SPTR マクロで使用できる文字列は255バイト分まで(バージョン1.04では4095バイト分まで)という制限があるので、注意が必要です。

SPTRとは別に、変数へのポインタを渡すマクロ「PTR」もあります。そこで、サイズの大きい文字列を渡したい場合には、いったん文字列を変数に格納した後で、その変数をPTRマクロで渡すようにすればいいでしょう。上のスクリプトは、次のように書くこともできます。

text1 = "WA_MACROを使ってます"
text2 = "API呼び出しテスト"
MessageBox PRMHWND, PTR(text1), PTR(text2), 0x30

パラメータ用のマクロ

関数呼び出し時のパラメータ用に、上で示した「SPTR」などの他にもいくつかのマクロが定義されています。以下に、それらをまとめておきます。

マクロ意味
PTR(v1)変数 v1 へのポインタ
SPTR(s1)文字列 s1 へのポインタ(最大4Kバイト)
WSPTR(s1)文字列 s1 のUnicode文字列へのポインタ(最大4Kバイト;2047文字)
PRMHINSTアプリケーションのインスタンスハンドル
PRMHWND描画中ウィンドウのハンドル
PRMHWNDN(n1)ウィンドウID n1 のウィンドウのハンドル
PRMHDC描画中ウィンドウの画面バッファのデバイスコンテキストのハンドル
PRMHDCN(n1)ウィンドウID n1 のウィンドウの画面バッファのデバイスコンテキストのハンドル
PRMHOBJ(n1)描画中ウィンドウ上にあるHSPオブジェクトID n1 のウィンドウハンドル

HSPではマクロ名を含めて大文字・小文字の区別はされませんから、小文字で「ptr(v)」などとすることが可能です。

以上のマクロは、関数呼び出し時のパラメータ指定に対してしようすることができます。逆に、別の目的(変数への代入など)には使用することができません。例えば、

p = PTR(v)             ; これは間違い
hwnd = PRMHWND         ; これは間違い

などとすることはできないのです。

戻り値用のマクロ

戻り値はマクロ名「DLLRET」で定義されています。これはllmodモジュールにおける戻り値用の変数 dllret と互換性を持たせるためにこのような形になっています(WA_MACROはllmodモジュールと同時に使用することができるようになっています)。この戻り値マクロはグローバル定義されており、モジュール領域の中からでもアットマーク「@」をつけることなく「DLLRET」(または「dllret」)だけの形で参照できるようになっています。

例えば、 CreateEllipticRgn 関数を使用して、円形のリージョンオブジェクトを作成する場合には以下のようにします(あらかじめgdi32.asをインクルードしておく必要があります)。

; 円形のリージョンオブジェクトを作成する
CreateEllipticRgn 0, 0, 300, 300
hRgn = dllret        ; リージョンのハンドル 

戻り値の取得に関しては、llmodモジュールと同じですね。ただ、 dllproc 命令の場合にはシステム変数 stat にも戻り値が格納されていましたが、WA_MACROの場合には stat への格納はされないので注意しましょう。

特殊な値を取得するマクロ

上述のパラメータ用マクロで取得できる値(例えば「PTR(v)」など)を変数での代入のために使用することはできませんでした。これを行なうために、別のマクロが定義されています。

マクロ意味
GetAddr v1, v2変数 v1 へのポインタを v1 に格納
GetHinst v1アプリケーションのインスタンスハンドルを v1 に格納
GetHwnd v1描画中ウィンドウのハンドルを v1 に格納
GetHwndN v1, n2ウィンドウID n2 のウィンドウのハンドルを v1 に格納
GetHdc v1描画中ウィンドウの画面バッファのデバイスコンテキストのハンドルを v1 に格納
GetHdcN v1, n2ウィンドウID n2 の画面バッファのデバイスコンテキストのハンドルを v1 に格納
GetHobj v1, n2描画中ウィンドウ上にあるHSPオブジェクトID n2 のウィンドウハンドルを v1 に格納
GetHobjN v1, n2, n3ウィンドウID n3 上にあるHSPオブジェクトID n2 のウィンドウハンドルを v1 に格納

例えば、GetAddrgetptr 命令とまったく同じ働きがあることが分かりますよね。つまり、関数のパラメータ以外に変数のアドレスを取得する必要がある場合には、これを使用すればいいのです。

その他のマクロ

これら以外にも、様々なマクロが定義されています。まず、以下の関数型マクロが定義されています。

マクロ意味
LOWORD(n1 )n1 の下位16ビット値(符号なし)
HIWORD(n1 )n1 の上位16ビット値(符号なし)
LOSWORD(n1 )n1 の下位16ビット値(符号付き)
HISWORD(n1 )n1 の上位16ビット値(符号付き)
LOBYTE(n1 )16ビット値 n1 の下位8ビット値(符号なし)
HIBYTE(n1 )16ビット値 n1 の上位8ビット値(符号なし)
LOSBYTE(n1 )16ビット値 n1 の下位8ビット値(符号付き)
HISBYTE(n1 )16ビット値 n1 の上位8ビット値(符号付き)
MAKELONG(n1, n2 )下位16bitが n1,上位16bitが n2 の値
RGB(nRed, nGreen, nBlue )指定した色のRGB値
GetRValue(nColor)RGB値 nColor から赤の値を取得
GetGValue(nColor)RGB値 nColor から緑の値を取得
GetBValue(nColor)RGB値 nColor から青の値を取得

例として、GetSysColor 関数を使ってシステムカラー(ここでは、3Dオブジェクトの表面色)を取得するスクリプトは以下のようになります。

#include "wam/user32.as"

GetSysColor 15            ; COLOR_3DFACE
r = GetRValue(dllret)     ; 赤の値
g = GetGValue(dllret)     ; 緑の値
b = GetBValue(dllret)     ; 青の値

mes "赤:"+r+" 緑:"+g+" 青:"+b
stop

また、Win32 APIではよく使われる以下の定数マクロが定義されています。

マクロ意味
NULL0ヌルポインタまたはヌルハンドル
FALSE0真偽値のうち偽を示す値
TRUE1真偽値のうち真を示す値(通常はTRUEかどうかで判断するのではなく、FALSEであるかないかで判断すべき)
MAX_PATH260ファイルパス・ファイル名を格納する文字列変数の確保するべきサイズ

これらのマクロは、他の人が公開しているモジュールの中でも同じように定義されている場合があり、そのようなモジュールとWA_MACROを同時に使用すると、マクロ多重定義によるエラーが発生することがあるので注意してください。

WA_MACROを使用する際の注意点

WA_MACROではシステムDLLが提供する関数をマクロ定義していますが、いくつかの関数ではHSPの命令と名前の衝突を起こしてしまっているので、次のような措置がとられています。

これらの関数を使用する場合には注意しましょう。