DLLの関数を呼び出す(独自拡張)

関数および副プログラムをDLLを利用して定義することができる。内部,外部のどちらでもよい(DEF文には適用できない)。
DLLを利用して定義する関数(または,副プログラム)では, FUNCTION行(またはSUB行)と,END FUNCTION行(またはEND SUB行)の間に次の形式のASSIGN文を書く。

ASSIGN DLLファイル名 ,関数名
DLLファイル名,関数名は,文字列定数を書く。


FUNCTION GetVersion
ASSIGN "kernel32.dll","GetVersion"
END FUNCTION
DLLファイル名は,利用しようとする関数を含むDLLの名称を指定する。関数名は,DLL内で登録されている名称を指定する。関数名は,英字の大小の違いを識別するので注意。

数値型の引数は上位桁を切り捨てた32ビット整数として評価して渡す。副プログラムの場合であっても変数引数とはならず,常に値引数になる。
文字列型の引数は,1文字目へのポインタ(32ビット)として渡される。ただし,空文字列のときはヌルへのポインタではなく,ヌルを渡す。BASICの文字列はヌルで終端された文字列として利用できる。
引数は,末尾の引数から順にスタック上に積まれる。DLLの関数は,制御を戻す前にスタック上の引数を削除しなければならない。
数値関数として定義するときは,DLLの関数から制御が戻されたときのEAXレジスタの値が関数値となる。この値は,常に32ビットの符号付整数として解釈する。
文字列関数として定義する場合,対象とするDLL関数は,ヌル終端のASCII(またはShift-JIS)文字列へのポインタを返す関数でなければならない。

例1
DECLARE EXTERNAL FUNCTION MesBox
LET n=MesBox(0,"Hello","BASIC",3)
PRINT n
END
EXTERNAL FUNCTION MesBox(owner,text$,caption$,flag)
ASSIGN "user32.dll","MessageBoxA"
END FUNCTION

変数のアドレスを引数として要求するDLL関数を呼び出すときは,文字列変数を引数にすることができる。REPEAT$関数などを利用して,引数として与える文字列変数の文字数をDLLの関数が必要とする大きさ以上としておく。この変数の値は他の変数から代入して作成したものであってはならず,また,この変数は他の変数に代入したことのあるものであってもならない。受け取った値は部分文字列指定を利用して取り出す。この変数を使用するプログラム単位でOPTION CHARACTER BYTEを宣言しておけば,文字列変数をバイト単位のバッファとして使える。
例2
DECLARE EXTERNAL FUNCTION CurrDir$
PRINT CurrDir$
END
EXTERNAL FUNCTION CurrDir$
OPTION CHARACTER BYTE
FUNCTION GetCurrentDirectory(n,s$)
ASSIGN "kernel32.dll","GetCurrentDirectoryA"
END FUNCTION
LET s$=Repeat$(" ", 200)
LET n=GetCurrentDirectory(200,s$)
LET CurrDir$=s$(1:n)
END FUNCTION

新規にダイアログを生成するDLLを実行するとテキスト出力の生成が阻害されることがある。その種のDLLを利用する場合は,次の形式のASSIGN文を書く。
ASSIGN DLLファイル名 ,関数名 ,GUI

実数値を取るDLL関数を利用する場合は,次の形式のASSIGN文を書く。
ASSIGN DLLファイル名 ,関数名 ,FPU
この形のASSIGN文を実行すると,FPUのスタックトップレジスタをPOPし,その値を関数の値とする。

<補足> DLLからWindowsの例外を受け取ると,ASSIGN文でExtype=-9900の例外を生成する。但し,DLLで発生する可能性のある例外はDLLの内部で処理しておくべきである。
<補足> ASSIGN文はFPUの制御wordを保存しないので,DLLでFPUの制御wordを変更したときは,戻る前に復元しなければならない。
<参考> 引数の受け渡し方に関する規約(呼出し側は引数を逆順にスタックに積み,スタック上の引数の解放は呼び出された側が行う)はWindows APIのものと同じである。
<Note> DLLは翻訳時にロードされる。指定されたDLLが他のDLLにリンクしていてそのDLLがロードできないためにエラーになる場合でも,プログラムで指定したDLLの名称で文法の誤りを表示する。
<Note> 引数の個数の誤りは翻訳時にも実行時にもチェックされない。引数の個数の誤りは悲惨な結果をもたらす。

<参考> 32ビットの符号つき整数nを符号なし整数の16進表記文字列に変換する関数
BSTR$(MOD(n, 4294967296),16)。

<参照> ORD関数とCHR$関数,部分文字列指定