Sometimes we need to give different type of parameters to our
C/C++ functions e.g. we may need more then 12 parameters or we are
using code from someone else who requires some integer parameters.
This gap is closed by
dlcallex
.
The syntax of
dlcallex
is:
err = dlcallex (h, "func", param, opt)
with h
a DLL handle, func
a DLL function,
param
a list of an arbitrary number of parameters (only
numeric or text !!) and opt
an optional list which
specifies the elements of param
more.
Let us rewrite our slightly modified
dlcallex1.xpl
such that we use
dlcallex
h = dlopen("dlcallex1.so") x = (1:3)~(4:6)~(7:9) ; create a 3x3 matrix instead of 10x1 s = 0 n = rows(x) x ; param = list (x, n, s) ; build parameter list byrow = 0|0|0 ; actually this is the default type = 8|8|8 ; actually this is the default opt = list (type, byrow) ; build parameter description list ; err = dlcallex(h, "sumd8", param, opt) param.s ; get the result of 45 = 1+...+9 back
which prints finally the result of 45 in the output window.
We see already that the list param
could contain an
arbitrary number of arguments. Thus the corresponding C program
dlcallex1.c
has to change too:
#include "dll.h" EXTERN int EXPORT sumd8 (int argc, int *type, voidp *ptr) { long i, nn; DBL8 *x, *n, *s; x = (DBL8 *) ptr[0]; n = (DBL8 *) ptr[1]; s = (DBL8 *) ptr[2]; nn = (long) *n; *s = 0; for (i=0; i<nn; i++) *s += *(x+i); return (0); }
The first parameter argc
tells us how many parameters
are given by the user. The second parameter type
tells us
which type the parameter given to our function sumd8
has.
This is identically to the list given in opt.type
. The
following types are possible:
XploRe object | C/C++ data type | entry in opt.type |
numeric | 8 byte float | 8 |
4 byte float | 4 | |
numeric | 8 byte integer | -8 |
4 byte integer | -4 | |
2 byte integer | -2 | |
1 byte integer | -1 | |
text | 1 byte char | -1 |
Note that we can not take any responsibility for a successful
conversion. For example the Symantec compiler does not provide a 8
byte integer. Also the conversion for a float value to a 1 byte
integer will fail if the float values are outside the range -126
till +127.
The third parameter ptr
is a set of pointers on
pointers which contain the data from XploRe. Actually we could
have used void**
but it seems that the Borland compiler
does not like such a definition, thus we have defined
typedef void* voidp;
.
The first step in the program is to assign the elements to the
"right" pointers. Since we know we have exactly three double
pointers there is no need to check argc
or type
. The
second step is to compute the sum of all values.
Note that we use the macro DBL8
rather than
double
. DBL8
stands for an 8 byte float value which
may not be the double
data type in all C/C++ compilers.
According to the table before we define also DBL4
,
INT8
, INT4
, INT2
and INT1
.
Since we are using quite small numbers we could do the same
just using 1 byte integers. Here are the according XploRe program
dlcallex2.xpl
h = dlopen("vecsum.so") x = (1:3)~(4:6)~(7:9) ; create a 3x3 matrix instead of 10x1 s = 0 n = rows(x) x ; param = list (x, n, s) ; build parameter list byrow = 0|0|0 ; actually this is the default type = -1|8|-1 opt = list (type, byrow) ; build parameter description list ; err = dlcallex(h, "sumd8", param, opt) param.s ; get the result of 45 = 1+...+9 back
and the C/C++ program dlcallex2.c
#include "dll.h" EXTERN int EXPORT sumi1 (int argc, int *type, voidp *ptr) { long i, nn; DBL8 *n; INT1 *x, *s; x = (INT1 *) ptr[0]; n = (DBL8 *) ptr[1]; s = (INT1 *) ptr[2]; nn = (long) *n; *s = 0; for (i=0; i<nn; i++) *s += *(x+i); return (0); }
Note that we have used here mixed parameters. The first
parameter is 1 byte integer, the second is 8 byte float and the
last parameter again 1 byte integer.
At last, let us talk about the setting in opt.byrow
. For
each parameter it can take the value zero or non-zero. By default
the value zero is used which means the data in a matrix are stored
columnwise.
Consider the matrix x
in XploRe which prints as
Contents of x [1,] 1 4 7 [2,] 2 5 8 [3,] 3 6 9
The pointer x
in dlcallex1.c
contains the
values
x = {1, 2, 3, 4, 5, 6, 7, 8, 9}
If the entry in opt.byrow
is non-zero then the pointer
x
contains the values
x = {1, 4, 7, 2, 5, 8, 3, 6, 8}
which means the data are stored rowwise.
To test the functionality of
dlcall
and
dlcallex
you may use our test programs:
dltestex.xpl
(XploRe program) and
vecsumex.C
(C++program).
Especially the last routine sumc1
is interesting since
it shows how to transfer a single string.