| You can pass closures to C as C functions in TXR Lisp, a language I created. Example: http://rosettacode.org/wiki/Window_creation#Win32.2FWin64 In this program, a translation of Microsoft's "Your First Windows Program" from MSDN, defun is used to define a WindowsProc callback. defun generates a lambda under the hood, which carries a lexical scope. The lambda is passed directly to Win32 as a callback, which is nicely called for repainting the window. (Or at least, things appear that way to the programmer.) Setting this up requires a few steps. We need a target function, of course, which can be any callable object. Then there is this incantation: (deffi-cb wndproc-fn LRESULT (HWND UINT LPARAM WPARAM))
The deffi-cb operator takes a name and some type specifications: return type and parameters. The name is defined as a function; so here we get a function called wndproc-fn. This function is a converter. If we pass it a Lisp function, it gives back a FFI closure object.Then in the program, we instantiate this closure object, and stick it into the WNDPROC structure as required by the Windows API. Here we use the above wndproc-fn converter to obtain WindowProc in the shape of a FFI closure: (let* ((hInstance (GetModuleHandle nil))
(wc (new WNDCLASS
lpfnWndProc [wndproc-fn WindowProc]
...
The lpfnWndProc member of the WNDCLASS FFI structure is defined as having the FFI type closure; that will correspond to a function pointer on the C side. The rest is just Windows: (RegisterClass wc)
register the class, and then CreateWindow with that class by name and so on. |
http://www.kylheku.com/cgit/txr/tree/tests/017/qsort.tl
It's done in two ways, as UTF-8 char * strings and as wchar_t * strings.
What's used as the callback is the function cmp-str which is in TXR Lisp's standard library. A lambda expression could be used instead.
Also tested is the perpetration of a non-local control transfer out of the callback, instead of the normal return. This properly cleans up the temporary memory allocated for the string conversions.