Prev Menu Next

Invoking a DLL function (Original Enhancement, Windows only)
Internal or external functions and subprograms except DEF can be defined using a DLL.
In that case, the following style of ASSIGN statement is written between the FUNCTION line and the END FUNCTION line or the SUB line and END SUB line.
ASSIGN DLL-file-name , function-name
where DLL-file-name and function-name are string constants.
Example
`FUNCTION GetVersion
ASSIGN "kernel32.dll","GetVersion"
END FUNCTION`
DLL-file-name indicates the DLL that contains the function we want to use. Function-name indicates the function in the DLL. Function-name is case sensitive.
Numeric arguments are evaluated as 32bit integers cutting off the upper digits to be passed. The arguments are always passed by value even if the procedure is a SUB program.
A string argument is passed a 32bit pointer that points the first character of it. But it is a null string, the null pointer shall be passed, which is not a pointer to a null string.
Arguments are laid into the stack in order of last parameter first. the DLL function to be called must erase the arguments on the stack before it leaves.
When a function is defined as numerical, the result of it shall be the value of EAX register at the time when the controls returns. That value is appreciated as a signed integer.
When a function is defined as a string function, it must be a function that returns a pointer that points a null terminated ASCII (or ANSI) string.
If a DLL that uses GUI fails, use the following form of an ASSIGN statement.
This designates the DLL to be executed on the main thread.
ASSIGN DLL-file-name, function-name, GUI
Example 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",GUI
END FUNCTION`
We use a string variable for a DLL function's argument which is an address of a variable. We prepare sufficient size of memory that the DLL function requires for the argument by making the length of the string as long as required, using a REPEAT$-function or so. We cannot make that string variable by substituting another string variable for it. And that string variable cannot have been substituted for any other string variable.
We can get the received value using substring operation. A string variable can be used a byte buffer when OPTION CHARACTER BYTE is declared in the program unit where the substring operation shall be done.
Example 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`
To use a DLL which returns the value on the FPU register, write a ASSIGN statement of following style .
ASSIGN DLL-file-name, function-name ,FPU
When a ASSIGN statement of this style is executed, the stack top FPU resister shall be popped and function value shall be its value.
To invoke a DLL compiled with CDECL calling convention, write following style ASSIGN statements.
ASSIGN DLL-file-name , function-name ,CDECL
ASSIGN DLL-file-name , function-name ,GUI, CDECL
ASSIGN DLL-file-name , function-name ,FPU, CDECL
<Supplement.> An ASSIGN statement raises an exception of extype -9900 when it receives an OS exception, while exceptions that might be occur in a DLL ought to be handled in the DLL.
<Supplement> An ASSIGN statement does not preserve the FPU flags, the DLL function must restore the FPU flags before the return if it alters them.
<Notice.> The DLL is loaded on compiling. When another DLL linking it occurs a load error, the load error shall be shown with the name of specified in the program.
<Notice.> An error on the number of arguments shall not be checked when the program is compiled and when the program runs. Thus a mistake on the number of parameters causes a miserable result.

<Note.> A function that converts a signed 32 bit integer to the hexadecimal representation of its unsigned evaluation.
BSTR$(MOD(n, 4294967296),16)

<Reference.> ORD-function and CHR$-function, Substring
Supplied function
ANSI$(string-expression)
Convert to the Windows ANSI string.
Example.
`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$(string-expression)
Convert to the Windows Wide character string(UTF-16).
Example.
`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$(string-expression)
Convert a Windows ANSI-string to the internal string(UTF-8).
ImportWIDE$(string expression)
Convert a Windows Wide character string to the internal string(UTF-8)
WINHANDLE(s$)
The handle of the system window (or control) to be passed to Win32 API.
s$ is one of the following.
`"TEXT", "GRAPHICS", "INPUT", "CHARACTER INPUT"， "LOCATE", "LOCATEVALUE"`
Differences in case are ignored.
IF another one is designated, the function result shall be zero, generating no exception.
Example 1.

    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