#### 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.