All Manuals > LispWorks Foreign Language Interface User Guide and Reference Manual > 4 Defining foreign functions and callables

NextPrevUpTopContentsIndex

4.1 Foreign callables and foreign functions

The two main macros for interfacing LispWorks with a foreign language are define-foreign-callable which defines Lisp functions that can be called from the foreign language, and define-foreign-function which defines a short linking function that can call functions in a foreign language.

In Introduction to the FLI we defined a foreign function for calling the Win32 function SetCursorPos. The code for this example is repeated here.

(fli:define-foreign-function (set-cursor-position "SetCursorPos")
    ((x :long)
     (y :long))
  :result-type :boolean)

A FLI foreign function calling some C code. is an illustration of set-cursor-position, represented by a square, calling the C code which constitutes SetCursorPos.

Figure 4.1 A FLI foreign function calling some C code.

The next diagram, C calling a callable function in Lisp., illustrates a callable function. Whereas a foreign function consists of a Lisp function name calling some code in C, a callable function consists of Lisp code, represented by an oval in the diagram, which can be called from C.

Figure 4.2 C calling a callable function in Lisp.

Callable functions are defined using fli:define-foreign-callable, which takes as its arguments, amongst other things, the name of the C function that will call Lisp, the arguments for the callable function, and a body of code which makes up the callable function.

To call a Lisp function from C or C++ you need to define it using fli:define-foreign-callable. Then call fli:make-pointer with the :symbol-name argument and pass the result to C or C++ as a function pointer.

For the purpose of creating a self-contained illustration in Lisp, the following Lisp code defines a foreign callable function that takes the place of the Windows function SetCursorPos.

(fli:define-foreign-callable ("SetCursorPos" 
                              :result-type :boolean)
  ((x :long) (y :long))
  (capi:display-message 
     "The cursor position can no longer be set"))

Supposing you had the above foreign callable defined in a real application, you would use

(make-pointer :symbol-name "SetCursorPos")

to create a foreign pointer which you pass to foreign code so that it can call the Lisp definition of SetCursorPos.

A FLI foreign function calling a callable function. illustrates what happens when set-cursor-position is called. The foreign function set-cursor-position (represented by the square) calls what it believes to be the Windows function SetCursorPos, but the callable function (represented by the oval), also called SetCursorPos, is called instead. It pops up a CAPI pane displaying the message "The cursor position can no longer be set".

Figure 4.3 A FLI foreign function calling a callable function.

For more information on calling foreign code see define-foreign-function.

For more information on defining foreign callable functions see Strings and foreign callables and define-foreign-callable.

For information on how to create a LispWorks DLL, see "Creating a dynamic library" in the LispWorks User Guide and Reference Manual .

For some complete examples of building a LispWorks DLL, then loading and calling it from foreign code, see "Delivering a dynamic library" in the LispWorks Delivery User Guide .

4.1.1 Strings and foreign callables

To interface to a C function which takes a pointer to a string form and puts a string in the memory pointed to by result, declared like this:

void evalx(const char *form, char *result);

you would define in Lisp:

(fli:define-foreign-function evalx 
    ((form (:reference-pass :ef-mb-string))
     (:ignore (:reference-return
               (:ef-mb-string :limit 1000)))))

and call

(evalx "(+ 2 3)")
=>
"5"

Now suppose instead that you want your C program to call a similar routine in a LispWorks for Windows DLL named "evaluator", like this:

{
 typedef void (_stdcall *evalx_func_type)(const char *form, char *result);
 HINSTANCE dll = LoadLibrary("evaluator");
 evalx_func_type evalx = (evalx_func_type) GetProcAddress(dll, "evalx");
 char result[1000];
 evalx("(+ 2 3)", result);
 printf("%s\n", result);
}

You would put this foreign callable in your DLL built with LispWorks:

(fli:define-foreign-callable
    ("evalx" :calling-convention :stdcall)
    ((form (:reference :ef-mb-string
            :lisp-to-foreign-p nil
            :foreign-to-lisp-p t))
     (result (:reference (:ef-mb-string :limit 1000)
              :lisp-to-foreign-p t
              :foreign-to-lisp-p nil)))
  (multiple-value-bind (res err)
      (ignore-errors (read-from-string form))
    (setq result
          (if (not (fixnump err))
              (format nil "Error reading: ~a"
                      err)
            (multiple-value-bind (res err)
                (ignore-errors (eval res))
              (if (and (not res) err)
                  (format nil "Error evaluating: ~a"
                          err)
                (princ-to-string res)))))))

Note: you could use :reference-return and :reference-pass in the foreign callable definition, but we have shown :reference with explicit lisp-to-foreign-p and foreign-to-lisp-p arguments to emphasise the direction of each conversion.


LispWorks Foreign Language Interface User Guide and Reference Manual - 29 Sep 2017

NextPrevUpTopContentsIndex