DLLの関数を呼び出す(独自拡張)
整数型の変数を扱う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内で登録されている名称を指定する。関数名は,英字の大小の違いを識別するので注意。
浮動小数点数を扱うDLLには対応しない。
数値型の引数は上位桁を切り捨てた32ビットまたは64ビット整数として評価して渡す。副プログラムの場合であっても変数引数とはならず,常に値引数になる。
文字列型の引数は,1文字目へのポインタとして渡される。ただし,空文字列のときはヌルへのポインタではなく,ヌルを渡す。BASICの文字列はヌルで終端された文字列として利用できる。
ヌルポインタを空文字列として扱わないDLLに空文字列を渡したいときは,chr$(0)を利用する。
数値関数として定義するときは,値を符号付整数として解釈する。
文字列関数として定義する場合,対象とするDLL関数は,ヌル終端のASCII文字列へのポインタを返す関数でなければならない。
例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
Windows32ビットで CDECL呼出規約でコンパイルされたDLLを呼び出すときは,次の形式のASSIGN文を書く。
ASSIGN DLLファイル名 ,関数名 ,CDECL
ASSIGN DLLファイル名 ,関数名 ,GUI, CDECL
ASSIGN DLLファイル名 ,関数名 ,FPU, CDECL
Linux(32ビット)では,暗黙でCDECLを仮定する。StdCall呼び出し規約で作成されたDLLを呼び出すときは,上記のCDECLの替わりにSTDCALLを指定する。
<制限> ARM32/64版には,引数は最大12個の制限がある。
<補足> DLLからOSの例外を受け取ると,ASSIGN文でExtype=-9900の例外を生成する。但し,DLLで発生する可能性のある例外はDLLの内部で処理しておくべきである。
<補足> ASSIGN文はFPUの制御wordを保存しないので,DLLでFPUの制御wordを変更したときは,戻る前に復元しなければならない。
<Note> DLLは翻訳時にロードされる。指定されたDLLが他のDLLにリンクしていてそのDLLがロードできないためにエラーになる場合でも,プログラムで指定したDLLの名称で文法の誤りを表示する。
<Note> 引数の個数の誤りは翻訳時にも実行時にもチェックされない。
<補足> 64ビット環境では,2進モードで実行しても倍精度数53ビットの制限がある。1000桁モードや有理数モードで実行しても,内部処理の浮動小数点数を用いるので53ビットの制限がある。
<補足> GUIを用いるDLLを呼び出すと障害を起こす可能性がある。
<補足> Mac版はLinux版と同仕様だが,動作は未確認。
<参考> 32ビットの符号つき整数nを符号なし整数の16進表記文字列に変換する関数 BSTR$(MOD(n, 4294967296),16)。
<参照> ORD関数とCHR$関数,部分文字列指定
組込み関数(Windowsのみ)
ANSI$(文字列式)
WindowsのANSI文字(Shift-JIS)に変換する。
例
10 DECLARE EXTERNAL FUNCTION MesBox$
20 CALL MesBox(0,ANSI$("漢字"),ANSI$("BASIC"),3)
30 END
100 EXTERNAL SUB MesBox(owner,text$,caption$,flag)
110 ASSIGN "user32.dll","MessageBoxA", GUI
120 END SUB
WIDE$(文字列式)
WindowsのWide文字(UTF-16)に変換する。
例
10 DECLARE EXTERNAL FUNCTION MesBox$
20 CALL MesBox(0,WIDE$("髙木"),WIDE$("BASIC"),3)
30 END
100 EXTERNAL SUB MesBox(owner,text$,caption$,flag)
110 ASSIGN "user32.dll","MessageBoxW", GUI
120 END SUB
ImportANSI$(文字列式)
WindowsのANSI文字(Shift-JIS)を内部形式(UTF-8)に変換する。
ImportWIDE$(文字列式)
Wide文字(UTF-16)を内部形式(UTF-8)に変換する。
WINHANDLE(文字列式)
Win32APIに渡すための,BASICシステム自身のウィンドウ(またはコントロール)のハンドル値。
引数は,"MAIN", "TEXT", "GRAPHICS", "INPUT", "CHARACTER INPUT","TRACE", "LOCATE", "LOCATECHOICE"のいずれか。
大文字と小文字の違いは無視する。
上記以外を指定すると値が0になる(例外を生成しないので注意)。
例
100 DECLARE EXTERNAL SUB MoveTextWindow, ResizeTextWindow
110 FOR i=1 TO 5
120 PRINT "Hello"
130 CALL MoveTextWindow(i*100,i*60)
140 CALL ResizeTextWindow(320,160+i*20)
150 WAIT DELAY 1
160 NEXT i
170 END
180 EXTERNAL SUB MoveTextWindow(x,y)
190 SUB SetWindowPos(hwnd,HwndInsAfter,x,y,cx,cy,nFlags)
200 ASSIGN "user32.dll","SetWindowPos"
210 END SUB
220 CALL SetWindowPos(WinHandle("TEXT"),0,x,y,0,0,1)
230 END SUB
240 EXTERNAL SUB ResizeTextWindow(x,y)
250 SUB SetWindowPos(hwnd,HwndInsAfter,x,y,cx,cy,nFlags)
260 ASSIGN "user32.dll","SetWindowPos"
270 END SUB
280 CALL SetWindowPos(WinHandle("TEXT"),0,0,0,x,y,2)
290 END SUB