Updated October 2021; see History
To load/unload an external library:
xcall DYNLIB, dlctl {,lib, convention, stackspace}
To call a function in the external library:
xcall DYNLIB, dlctl, funcsig {,parms...}
(Windows and Linux only) DYNLIB provides a mechanism for A-ShellBASIC programs to dynamically access routines in external libraries written in C (or compiled to a C compatible object format), without the need for any special compile-time linking or modifications to A-Shell to support the external library. The fundamental difficulty here is the fact that third-party libraries may have many different calling conventions, and there is almost no limit to the variety of return types and parameter lists for the functions involved. DYNLIB deals with this variability by supporting a wide variety of the most common library calling conventions, and a flexible scheme for specifying function signatures so that the function arguments can be properly passed and converted.
Parameters
dlctl (ST_DYNLIBCTL) [in/out]
This is a structure containing various control parameters used and/or updated for every call. It is defined in ashinc:dynlib.def as:
defstruct ST_DYNLIBCTL
map2 handle,DLHANDLE ! handle to the external module
map2 opcode,b,4 ! see DCOP_xxx
map2 flags,b,4 ! flags (see DLF_xxx)
map2 status,i,4 ! see (DYNLIBE_xxx)
map2 syserr,i,4 ! system error set by called fun, e.g. GetLastError() for Windows; else errno
map2 lastfunc$,s,64 ! function signature of last called function
endstruct
Opcodes from ashinc:dynlib.def are:
Value |
Symbol |
---|---|
0 |
DCOP_LOAD |
1 |
DCOP_UNLOAD |
2 |
DCOP_CALL |
4 |
|
5 |
DCOP_GETREF |
lib (String) [in]
Used only for the load routine (opcode DCOP_LOAD), lib specifies the name of the external library. For Windows, this is just the DLL name (no path or extension needed, provided the DLL is in the standard search path, or in the A-Shell bin directory). For Linux, it will be a name like "libxl.so.1" which references a shared library in the system library path (typically /usr/lib). By convention, typically file in the /usr/lib directory is actually a symbolic link to the actual library file.
convention (Num) [in]
Used only for the load routine to specify the calling convention for the external library. See the DLCC_xxx codes defined in ashinc:dynlib.def for the possibilities. Note that the most common options are DLCC_C_X86_WIN32_STD for Windows DLLs, and DLCC_C_X86_CDECL for Linux.
stackspace (Num) [in]
Used only for the load routine to specify the amount of stack space to reserve for the library. 4 to 8K is typically plenty.
funcsig (String) [in]
This string is used in conjunction with a call to a library function (opcode DCOP_CALL) to declare the function name, return type, and expected parameter list. The format is:
funcname(pppp....)r
where:
• | funcname is the name of the function to call in the external library |
• | each p is a one letter code indicating the type of parameter from the table below |
• | r indicates the return type of the function, from the table below |
Code |
Description |
|
Code |
Description |
---|---|---|---|---|
a |
char * (convert ANSI to UTF8) |
|
L |
64 bit unsigned integer (x,8) |
A |
const char* (convert ANSI to UTF8) |
|
p |
(lower case "p") void*; see Output Parameters below |
B |
_Bool, bool (i,2) or i,4? |
|
P |
(upper case "P") similar to "p" but receives the size of a ">" argument. See Output Parameters below. |
c |
char (s,1) |
|
s |
short (i,2) |
C |
unsigned char (s,1) |
|
S |
unsigned short (b,2) |
d |
double (f8) |
|
u |
char * (from UTF8 string). See Output Parameters below. |
f |
float (f4) |
|
U |
const wchar * (from UTF8 string) |
h |
32 or 64 bit handle (x,8) |
|
v |
(lower case "v") void. See Output Parameters below. |
|
|
|
V |
(Upper case "V")const void *; like Z but is converted to NULL if the corresponding parameter value is "". See Output Parameters below. |
i |
int (i,4) |
|
w |
wchar_t * (s) |
I |
unsigned int (b,4) |
|
W |
const wchar_t * (s) |
j |
long (i,4) |
|
z |
char * (s,0) |
J |
unsigned long (b,4) |
|
Z |
const char * (s,0) |
l |
64 bit signed integer (x,8) |
|
> |
identifies an indirect output string parameter. See DYNLIB Indirect Output. |
Examples
C Function Prototype |
funcsig |
---|---|
void f1(); |
”f1()v” |
int f2(int, int); |
”f2(ii)i” |
long long f3(void*); |
”f3(p)L” |
void f3(int**); |
”f3(p)v” |
double f4(int, bool, char, double, const char*); |
”f4(iBcdZ)d” |
Following the function signature, the remaining parameters are the arguments being passed, followed by the parameter to receive the return value of the function.
Output Parameters
Parameters to be output or updated by the called routine should be defined using one of the p, P , u, v, w, or > codes. Codes u and w will convert ASCII / Latin1 strings used in the application to UTF8 or UNICODE-16 characters used by the called library routine, and vice versa if the parameter is updated by the routine. Code v is used for routines that do not return any value. See Indirect Output Parameters, for more details on the P and > codes.
Comments
See LIBXL.BSI in EXLIB:[908,68] for examples.
Because this is a bit tricky, if you have an external library you would like to interface with, you may want to consult with MicroSabio to help you evaluate it and get it started.
History
2021 October, A-Shell 6.5.1708: Fully implemented types "l" and "L," added type "h." These were required to support using DYNLIB to call 64 bit library routines. The "h" (handle) option in particular is needed to allow BASIC programs to interface with libraries that rely on handles (like AXL) and which may be either 32 or 64 bit.
2019 September, A-Shell 6.5.1667: Added type "P" which acts similarly to "p" but receives the size of a ">" argument. Useful for functions that return a pointer to a buffer in one argument and the size the buffer in another. The AXL function Fn'LibXL'GetPicture uses this technique.
2017 November, A-Shell 6.5.1621: Added parameter types ">" and "P", plus opcode DCOP_DEREF.
2017 November, A-Shell 6.5.1619: DYNLIB now supports up to four dynamic libraries simultaneously; previously it could only handle one at a time.
2017 January, A-Shell 6.3.1542: automatic conversion from ANSI to/from UTF8 now supported via the "A" (read only) and "a" (read/write) codes. This is used in the Linux version of the LIBXL API to handle accented and other special Latin1 characters.
2015 November, A-Shell 6.3.1500: Routine added to A-Shell. Initially for internal use only in conjunction with LibXL, later to be documented and made available to programmers. Documentation posted January 2017.
Subtopics