DYNLIB

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.SBR 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

DCOP_DEREF 

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

void* (any output vars probably need to use this)

B

_Bool, bool (i,2) or i,4?

 

P

similar to "p" but receives the size of a ">" argument.

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)

f

float (f4)

 

U

const wchar * (from UTF8 string)

h

32 or 64 bit handle (x,8)

 

v

void

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 additional detail here.

 

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.

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 type ">" and opcode DCOP_DEREF "dereferences."

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.