%|||% &|What |'''ffidl'''|& &|Where |http://elf.org/ffidl/|& &|Where |http://rutherglen.ics.mq.edu.au/~steffen/tcltk/ffidl/doc (dead)|& &|version |0.6|& &|Updated |??/2006|& &|Contact |mailto:rec@elf.org ([Roger E Critchlow%|%Roger E. Critchlow Jr.])|& ** See Also ** [Ffix - Ffidl eXtented]: an experimental wrapper to make foreign function calling easier ** Description ** '''ffidl''', "Foreign Function Interface with Dynamic Loading", by [Roger E Critchlow], is an [extension] which allows pure Tcl extensions to invoke functions in shared libraries without having to create any glue code. Ffidl supports calls in both directions between C/C++ and Tcl, and operates on a variety of platforms. The Tcl command specifies a function name, a library, a list of argument types, and a return type, and ffidl takes care of the details of setting up the arguments and invoking the C function. Using ffidl, a pure Tcl wrapper to a shared library can be created. Avaliable for [Linux], [Windows], and [Mac OS X]. modifications resulting in version 0.6 were contributed by [DAS]. ** Development ** [https://chiselapp.com/user/pooryorick/repository/ffidl%|%unofficial fossil repository]: no releases yet, but some minor fixes have been made. Unlike 0.6, below, it builds with Tcl-8.6. ** Obtaining ** [DAS] - I have updated [Ffidl] to support Darwin/[Mac OS X], as well as modernized it in other ways: * updates for 2005 versions of libffi & ffcall * TEA 3.2 buildsystem, testsuite * support for Tcl 8.4, TclpDlopen, Tcl_WideInt * fixes for 64bit LP64 * callouts & callbacks are created/used relative to current namespace (for unqualified names) * addition of [[ffidl::stubsymbol]] for Tcl/Tk symbol resolution via stubs tables * callbacks can be called anytime, not just from inside call-outs (using Tcl_BackgroundError to report errors) the testsuite is just the existing tests wrapped into .test files. [http://rutherglen.ics.mq.edu.au/~steffen/tcltk/ffidl/doc/%|%updated docs%|%]: [http://rutherglen.ics.mq.edu.au/~steffen/tcltk/ffidl/ffidl.tar.gz%|%source tarball%|%]: [http://rutherglen.ics.mq.edu.au/~steffen/tcltk/ffidl/ffidl-full.tar.gz%|%full source tarball%|%]: includes libffi and ffcall sources For MacOS users, an unofficial update version 0.6.1 can be found at * [http://www.categorifiedcoder.info/tcltk/ffidl/ffidl-0.6.1-darwin-9-univ.tar.gz%|%source code%|%] * [http://www.tcl.tk/starkits/ffidl0.6.1_ub.tgz%|%MacOS Universal Binary%|%] (tested on Leopard) Note that the binary package listed at http://elf.org/ffidl/ does not work on Tiger/Leopard (? only for PowerPC ?) A binary package for Win/Linux/Mac, unoficially versioned 0.6.1.1, is available at the [http://irrational-numbers.googlecode.com/files/ffidl-0.6.1.1.zip%|%irrational-numbers project%|%] Note that a little BUG has been fixed ("Ffidlrt.tcl does not work if installed in a path name with whitespaces"). Ffidl either uses unmodified [http://www.haible.de/bruno/gnu/ffcall-1.10.tar.gz%|%ffcall 1.10%|%] or the [http://rutherglen.ics.mq.edu.au/~steffen/tcltk/ffidl/libffi.tar.bz2%|%HEAD of libffi from the gcc CVS%|%] with a [http://rutherglen.ics.mq.edu.au/~steffen/tcltk/ffidl/libffi.diff%|%small patch%|%] to the buildsystem to make it build standalone (i.e. without relying on the gcc sourcetree structure) Note that libffi is under BSD license but ffcall is GPLd. [APN]: In response to a question on c.l.t [DAS] replied: no, ffidl uses either libffi or ffcall, but never both. If you use my 0.6 update to ffidl, the choice of libffi vs ffcall is a compile time option (with libffi being the default for GPL avoidance reasons). A ffidl binary built with the default configure options (or with -enable-libffi) will contain only BSD licensed code, whereas a ffidl built with --enable-ffcall will indeed become GPLd as a whole by virtue of static linking with ffcall. [http://rutherglen.ics.mq.edu.au/~steffen/tcltk/ffidl/ffidl.c.diff%|%The diff%|%] of ffidl.c against the 0.5 version [Mac OS X] ffidl binaries (with libffi) are available as tarball [http://rutherglen.ics.mq.edu.au/~steffen/tcltk/ffidl/binaries/darwin/%|%installer package or tarball%|%]. A [Windows] ffidl binary (with libffi) built with [MinGW] on WIndowsXP in VirtualPC is now also [http://rutherglen.ics.mq.edu.au/~steffen/tcltk/ffidl/binaries/windows/Ffidl0.6.zip%|%available%|%]. I have tested & exercised this quite extensively on [Mac OS X] 10.3 (with both libffi and ffcall), and have verified that it builds and passes the testsuite on Windows XP with [MinGW] (in Virtual PC on my Mac...). I have also built ffidl and run the testsuite on all the machines in the [http://sourceforge.net/docman/display_doc.php?group_id=1&docid=762#hosts%|%sourceforge compilefarm%|%]: hosts passing the test suite with both libffi and ffcall: * amd64-linux1 * alpha-linux1 * x86-linux1 * x86-linux2 * x86-solaris1 * x86-freebsd1 * x86-netbsd1 host core dumping when running the test suite (with both libffi and ffcall): * sparc-solaris1 hosts passing the test suite with ffcall, but where building the libffi library fails: * x86-openbsd1 * ppc-osx1 * ppc-osx2 the last two may be fixable by reverting to an earlier version of libffi ** Code Using Ffidl ** [always on top]: [http://wiki.tcl.tk/4016%|%wrapper code%|%] for [AutoIt]: [web2desktop]: [ZLM]: includes an example of using ffidl to set the Windows desktop background. [Custom Toplevel Frame]: [SeS] (26-10-2010): uses Ffidl to access DLL's and create customized toplevel frames in the Windows OS ** Example: The Tcl Library ** [PYK] 2014-09-19: In the following example, [Tcl C API] functions are called. One thing to note is how space for a pointer is passed into `Tcl_GetCwd`. ====== #! /bin/env tclsh package require Ffidl namespace eval ::ffidl { namespace export * namespace ensemble create } if {[namespace current] ne {::}} { namespace import ::ffidl } set tclso libtcl8.6.so #set tclso libtcl8.5.so #set tclso [ffidl::find-lib tcl8.6] set Tcl_CreateInterp_sym [ffidl symbol $tclso Tcl_CreateInterp] set Tcl_GetCwd_sym [ffidl symbol $tclso Tcl_GetCwd] set Tcl_InterpDeleted_sym [ffidl symbol $tclso Tcl_InterpDeleted] set Tcl_GetString_sym [ffidl symbol $tclso Tcl_GetString] set Tcl_EvalObjEx_sym [ffidl symbol $tclso Tcl_EvalObjEx] ffidl callout Tcl_CreateInterp {} pointer $Tcl_CreateInterp_sym ffidl callout Tcl_GetCwd {pointer pointer-var} pointer-utf8 $Tcl_GetCwd_sym ffidl callout Tcl_InterpDeleted pointer int $Tcl_InterpDeleted_sym ffidl callout Tcl_GetString pointer-obj pointer-utf8 $Tcl_GetString_sym ffidl callout TclEvalObjEx {pointer pointer-obj int} int $Tcl_EvalObjEx_sym set interp [Tcl_CreateInterp] set script {puts [pwd]} puts [Tcl_GetString $script] TclEvalObjEx $interp $script 0 set bufferPtr [binary format [ffidl info format pointer] 0] set pwd [Tcl_GetCwd $interp bufferPtr] puts $pwd ====== ** Examples ** [Getting Windows "special folders" with Ffidl]: [kostix] offers a solution for getting "special folders" on Windows platforms. While [TWAPI] can do this out-of-the-box, it doesn't work on Win9x and is big. [Ffidl] doesn't have these limitations. [calling Fortran routines in a DLL]: [AutoIt]: ffidl wrapper brought to you by [Michael Jacobsen] [Windows Desktop modifications with Ffidl]: playing around with [Microsoft Windows%|%Windows] desktop properties. ---- from [Rolf Schroedter] on c.l.t --- file foo.h: --- ======c int foo_init( int adr, int log ); int foo_done( void ); int foo_info( FOO_INFO *infoPtr ); /* FOO_INFO is a structure */ int foo_open( const char *port ); ====== --- file foo.tcl: --- ====== load ffidl05.dll set DLL foo.dll ffidl::callout foo_init {int int} int [ffidl::symbol $DLL foo_init] ffidl::callout foo_done {} int [ffidl::symbol $DLL foo_done] ffidl::callout foo_info {pointer-var} int [ffidl::symbol $DLL foo_info] ffidl::callout foo_open {pointer-utf8} int [ffidl::symbol $DLL foo_open] ====== ---- Explain [Rolf Schroedter]'s [screensaver] [http://groups.google.com/groups?th=ec295f4a4849b362%|%example%|%] ---- ====== #Rolf Schroedter #German Aerospace Center #Institute of Space Sensor Technology and Planetary Exploration load ffidl05.dll ffidl::callout dll_FindWindow {pointer-utf8 pointer-utf8} int [ffidl::symbol user32.dll FindWindowA] ffidl::callout dll_FindWindowTitle {int pointer-utf8} int [ffidl::symbol user32.dll FindWindowA] ffidl::callout dll_FindWindowClass {pointer-utf8 int} int [ffidl::symbol user32.dll FindWindowA] ffidl::callout dll_SetWindowPos {int int int int int int int} int [ffidl::symbol user32.dll SetWindowPos] ffidl::callout dll_SystemParametersInfo {int int pointer int} int [ffidl::symbol user32.dll SystemParametersInfoA] proc FindWindow { class title } { if { [string length $class] == 0 } { dll_FindWindowTitle 0 $title } elseif { [string length $title] == 0 } { dll_FindWindowClass $class 0 } else { dll_FindWindow $class $title } } proc SetWindowPos { hwnd after x y cx cy {flags 0} } { array set VAL {TOP 0 BOTTOM 1 TOPMOST -1 NOTOPMOST -2} set iAfter $VAL([string toupper $after]) dll_SetWindowPos $hwnd $iAfter $x $y $cx $cy $flags } proc SetupScreenSaver { bool } { dll_SystemParametersInfo 97 $bool 0 0 ;# SPI_SCREENSAVERRUNNING=97 } proc exit? {} { set answer [tk_messageBox -message "Really quit?" -type yesno -icon question] switch -- $answer { yes { SetupScreenSaver 0 exit } no {} } } proc ScreenSaver {win} { set size(X) [winfo screenwidth .] set size(Y) [winfo screenheight .] toplevel $win wm title $win "TclScreenSaver" ;# to find the window wm overrideredirect $win true $win configure -relief flat -bd 0 $win configure -cursor hand2 ;# Ohne cursor ??? update idletasks ;# virtually display $win, allows window to be found set hwnd [FindWindow "" "TclScreenSaver"] set res1 [SetWindowPos $hwnd TOPMOST 0 0 $size(X) $size(Y)] ;# ever makes full screen set res2 [SetupScreenSaver 1] canvas $win.c -background yellow -width $size(X) -height $size(Y) -relief flat -bd 0 pack $win.c -expand yes -fill both focus -force $win bind $win exit? bind $win {} } wm withdraw . ScreenSaver .scr ====== ---- from [Rob Hegt] on c.l.t, '''Subject: solution for regaining focus from OpTcl hosted ActiveX control''': ====== load lib/ffidl05.dll ffidl::callout dll_SetFocus {int} int [ffidl::symbol user32.dll SetFocus] proc GrabFocus {args} {dll_SetFocus [winfo id .]} ====== Then just bind GrabFocus to some event. In the post he uses