DLL 1.0.0 Win32/LinuxELF dll caller package for TCL

Contents


Description

Tcl tcl package ::dll allows the Win32 implementation of tcl to call C coded routines inside DLLs (Dynamically Loaded Libraries). At present this should be considered alpha software as far as unicode is concerned. It passes all my tests with 8.2, but I have too little experience with Tcl other than 8.0.?. Remember too that libraries like Kernel32 can do pretty much anything to your system. You have been warned! Provisional callback arguments are allowed. I have succeded with preliminary work at a linux ELF implementation using dlopen etc. I compiled this using gcc with the makefile in the unix subdirectory. This version works with Tcl 8.2 and above. It was linked with the stubs library to make it more version proof.

Another package called Ffidl has been developed by Roger E. Critchlow Jr and as this package supports more platforms and is arguably better structured, ::dll should now be considered deprecated.


::dll::call

Synopsis

package require dll or load dll02
::dll::call path name returndef argdefs...
::dll::call @addr offs returndef argdefs...
::dll::call @@vec index returndef argdefs...


Tthe first form attempts to call procedure name in DLL path with argument list defined by argdefs and return value defined by returndef.

In the second form @addr is taken as an address and offs is added to form the address of the function to call.

In the third form @@vec is taken as the address of a vector of function pointers and index is taken as the element of this vector to use as the address of the function to call.
 
Returndef Argdef
v No return value {*n var}

{*sn var}

Pointer to a tcl variable named var. If var doesn't exist it will be created and assigned a string of length n. Eg {*256 buffer}. If n is omitted the variable must exist; otherwise it will be created to have the specified length in bytes. If the integer is preceded by s then the created variable will be truncated to the first zero byte.
i
4 byte integer
{i intvalue} The argument is a 4byte value. Eg {i 2021}
f
4byte float
{f floatvalue} The argument is a double value which is passed as a float.
d
8byte double
{d doublevalue} The argument is a double value. Eg {d 4.7}
n
an integer indicates a binary string of length n bytes should be returned
{b string} A string value. The binary command can be used to create this. Eg {b {this is a string}}. The whole string is passed as a value.
{s string} A constant string to be passed by address. Example {s {c:\windows\media\chord.wav}
{n string} An n byte binary value. Differs from argtype b in that the length is fixed. Example {7 S123456}
{@ Callback} A predefined callback At present only synchronous callbacks are supported.


::dll::callback

Synopsis

::dll::callback cdecl cbname tclname returndef argdefs...
::dll::callback stdcall cbname tclname returndef argdefs...
::dll::callback delete pattern
::dll::callback info pattern


The cdecl and stdcall subcommands create callback routines which may be used with the @ argument descriptor for the ::dll::call command. The cbname argument is the internal name by which the callback is known. The tclname argument is the name of a tcl proc which will effectively be substituted for the callback routine. The delete and info subcommands delete or return information about callbacks whose internal names match a pattern.
 
Callback Returndef Callback Argdef
v No return value Not allowed
i
4 byte integer
The argument is a 4byte value. It will be passed as an int Tcl_Object
f
4byte float
The argument is a float value which is passed as a double Tcl_Object..
d
8byte double
The argument is a double value which is passed as a double Tcl_Object..
bn
indicates a binary string of length n bytes should be returned
A binary string value. It will be passed to the tcl proc as a string of the right length (I hope). The binary command can be used to interpret this. 
s A constant string address. At present this is like the i return as I'm unsure how to create persistent string values which can be reclaimed. A constant null terminated string to be passed by address. This will be passed to the tcl proc as a string object.


::dll::declare

Synopsis

::dll::declare  path routine tclprocname returndefargdefs...
::dll::declare  @addr offs tclprocname returndefargdefs...
::dll::declare  @@vec index tclprocname returndefargdefs...
This command predeclares a TCL  proc named tclprocname as an interface to routine in dll path. Tthe returndef and argdefs are similar to those for the command  ::dll::call above, but if no value is supplied for an argdef (ie only a type is supplied) then the argument is made into a free argument of the created proc and must be supplied when the proc is called. Declared procsare in general more efficient when called than using ::dll::call. As an example on my machine (333Mhz Pentium Pro). The second and third forms supply the function address similarly to ::dll::call.
proc CFunc_i {i j} {return [::dll::call ./objs/testdll.dll func_i  i  [list i $i] [list i $j]]}
::dll::declare ./objs/testdll.dll func_i DFunc_i i i i
time {CFunc_i 1 2} 1000000 --> 40 microseconds
time {DFunc_i 1 2} 1000000 --> 3 microseconds
Supplied values are pre-evaluated at declare time; this means that constant callbacks must exist at declare and use time at present deleting such a callback would cause problems. 

::dll::get_interp

Synopsis

::dll::get_interp
Gets the address of the calling interpreter as an integer; this is a special hack to allow us to pass an Tcl_Interp pointer to routines in tcl80 etc. 

::dll::setoffs

Synopsis

::dll::setoffs integer [s|i|d|f|<integer>][:<integer>]+ [value]
Sets or gets an indirect value from a known address integer.The indirection (second) argument has  the form typecode[:offset]+ ie a typeletter which can be one of i, d, f, s or an integer meaning the pointed at final value is an integer, double, float, null terminated string or nbyte value followed by one or more : offset pairs. For each : (colon) except the first an indirection through the pointer is performed and the following integer is added as a byte offset. In the two argument form the the pointed at value is the result, in the three argument form the third argument is copied to the address determined by the pointer and the original value is returned. 

::dll::int2str

Synopsis

::dll::int2str integer
Some APIs pass either pointers to strings or integers with runtime tests being used to determine whether the actual passed value is a string or a meaningful integer. If an integer is known to be a string pointer this function can be used to obtain the string.

::dll::dinfo

Synopsis

::dll::dinfo pattern
Returns information about declared aliases which match pattern.


Testing

The dll loader can be tested using the files testdll.c & dlltest.tcl. The existing tests work under both Win32 and Linux ELF x86. The tests assume that the created dll (or .so) file is in ./objs or ./unix. Normally running tclsh dlltest.tcl should produce no output, but will indicate any errors that are found. If you find an error please send me the output. Clearly I cannot test all possible function signatures, so if you have a possible bug case please try and add it to testdll.c (in as simple a form as possible) and send me the testcase.


Examples

On my Win95 system this produces '10 C:\WINDOWS' and a list of hex toplevel window numbers. Other examples are in the files example.tcl and demo.tcl.

 

Download

You can download the file dll.zip. Good luck and be careful. All comments welcome.

Thanks

Erol Johnson  <earl-johnson@erols.com> forced me to consider the declare command by showing me it could be made more efficient.


Robin's Home Page