Next: , Previous: Windows Types, Up: Foreign function interface


18.2.2 Windows Foreign Procedures

Foreign procedures are declared as callable entry-points in a module, usually a dynamically linked library (DLL).

— procedure: find-module name

Returns a module suitable for use in creating procedures with windows-procedure. Name is a string which is the name of a DLL file. Internally, find-module uses the LoadLibrary Win32 API, so name should conform to the specifications for this call. Name should be either a full path name of a DLL, or the name of a DLL that resides in the same directory as the Scheme binary SCHEME.EXE or in the system directory.

The module returned is a description for the DLL, and the DLL need not necessarily be linked at or immediately after this call. DLL modules are linked on need and unlinked before Scheme exits and when there are no remaining references to entry points after a garbage-collection. This behavior ensures that the Scheme system can run when a DLL is absent, provided the DLL is not actually used (i.e. no attempt is made to call a procedure in the DLL).

— variable: gdi32.dll

This variable is bound to the module describing the GDI32.DLL library, which contains the Win32 API graphics calls, e.g. LineTo.

— variable: kernel32.dll

This variable is bound to the module describing the KERNEL32.DLL library.

— variable: user32.dll

This variable is bound to the module describing the USER32.DLL library. This module contains many useful Win32 API procedures, like MessageBox and SetWindowText.

— special form: windows-procedure (name (parameter type) ...) return-type module entry-name [options]

This form creates a procedure, and could be thought of as “foreign-named-lambda”. The form creates a Scheme procedure that calls the C procedure identified by the exported entry point entry-name in the module identified by the value of module. Both entry-name and module are evaluated at procedure creation time, so either may be expression. Entry-name must evaluate to a string and module must evaluate to a module as returned by find-module. These are the only parts of the form that are evaluated at procedure creation time.

Name is the name of the procedure and is for documentation purposes only. This form does not define a procedure called name. It is more like lambda. The name might be used for debugging and pretty-printing.

A windows procedure has a fixed number of parameters (i.e. no `rest' parameters or `varargs'), each of which is named and associated with a windows type type. Both the name parameter and the windows type type must be symbols and are not evaluated. The procedure returns a value of the windows type return-type.

The following example creates a procedure that takes a window handle (hwnd) and a string and returns a boolean (bool) result. The procedure does this by calling the SetWindowText entry in the module that is the value of the variable user32.dll. The variable set-window-title is defined to have this procedure as it's value.

          (define set-window-title
            (windows-procedure
             (set-window-text (window hwnd) (text string))
             bool user32.dll "SetWindowText"))
          
          (set-window-title my-win "Hi")
                                     #t
                                   ;; Changes window's title/text
          
          set-window-title           #[compiled-procedure  ...]
          set-window-text          error-->  Unbound variable

When there are no options the created procedure will (a) check its arguments against the types, (b) convert the arguments, (c) call the C procedure and (d) convert the returned value. No reversion is performed, even if one of the types has a reversion defined. (Reverted types are rare [I have never used one], so paying a cost for this unless it is used seems silly).

The following options are allowed:

with-reversions
The reversions are included in the type conversions.
expand
A synonym for with-reversions.
Scheme code
The Scheme code is placed between steps (a) and (b) in the default process. The Scheme code can enforce constraints on the arguments, including constraints between arguments such as checking that an index refers to a valid position in a string.

If both options (i.e. with-reversions and Scheme code) are used, with-reversions must appear first. There can be arbitrarily many Scheme expression.