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


18.2.1 Windows Types

Foreign types are designed to represent a correspondence between a Scheme data type that is used to represent an object within the Scheme world and a C data type that represents the data object in the C world. Thus we cannot manipulate true C objects in Scheme, nor can we manipulate Scheme objects in C.

Each foreign type has four aspects that together ensure that the correspondence between the Scheme and C objects is maintained. These aspects are all encoded as procedures that either check for validity or convert between representations. Thus a foreign type is not a declarative type so much as a procedural description of how to pass the type. The underlying foreign procedure call mechanism can pass integers and vector-like Scheme objects, and returns integer values. All other objects must be translated into integers or some other basic type, and must be recovered from integers.

The aspects are:

check
A predicate that returns #t if the argument is of an acceptable Scheme type, otherwise returns #f. The check procedure is used for type-checking.
convert
A procedure of one argument which returns a Scheme object of one of the basic types. It is used to convert an object into a `simpler' object that will eventually be converted into a C object. The legal simpler objects are integers and strings.
return-convert
A procedure of one argument that, given an integer, returns a Scheme object of a type satisfying check. Its purpose is to convert the result returned by the foreign procedure into a Scheme value.
revert
Some C procedures modify one or more of their arguments. These arguments are passed by reference, i.e. as a pointer to their address. Since a Scheme object might have a different memory layout and storage conventions, it must be passed by copy-in and copy-out rather than by reference. Revert is a procedure of two parameters, the original object passed and the result of convert on that object. Revert may then inspect the converted object and copy back the changes to the original.
— special form: define-windows-type name check convert return revert
— special form: define-similar-windows-type name model [check [convert [return [revert]]]]

Both forms define a windows type. The first form defines a type in terms of its aspects as described above. The second defines the type as being like another type, except for certain aspects, which are redefined. Name is the name of the type. Model is the name of a type. Check, convert, return and revert are procedures or the value #f. A #f means use the default value, which in the second form means use the definition provided for model. The defaults are

check
(lambda (x) #t), i.e. unchecked.
convert
(lambda (x) x), i.e. no translation performed.
return
(lambda (x) x), i.e. no translation performed.
revert
(lambda (x y) unspecific), i.e. no update performed

The unchecked windows type (see below) is defined as:

          (define-windows-type unchecked #f #f #f #f)
     

Windows types are not first class values, so they cannot be stored in variables or defined using define:

          (define my-type unchecked)            error-->  Unbound variable
          (define-similar-windows-type my-type unchecked)
                                                ;; the correct way
     

Scheme characters must be converted to integers. This is accomplished as follows:

          (define-windows-type char
             char?          ; check
             char->integer  ; convert
             integer->char  ; convert return value
             #f             ; cannot be passed by reference
          )
     
— windows type: unchecked

The type which is not checked and undergoes only the basic conversion from a Scheme integer to a C integer or from a Scheme string to a C pointer to the first byte of the string. Returned unchecked values are returned as integers.

— windows type: bool

Scheme booleans are analogous to C integers 0 and 1. Windows type bool have been defined as:

          (define-windows-type bool
             boolean?
             (lambda (x) (if x 1 0))
             (lambda (x) (if (eq? x 0) #f #t))
             #f)
     
— windows type: char

Scheme characters are converted into C objects of type char, which are indistinguishable from small integers.

— windows type: int
— windows type: uint
— windows type: long
— windows type: ulong
— windows type: short
— windows type: ushort
— windows type: word
— windows type: byte

Various integer types that are passed without conversion.

— windows type: string

A string that is passed as a C pointer of type char* to the first character in the string.

— windows type: char*

A string or #f. The string is passed as a pointer to characters. The string is correctly null-terminated. #f is passed as the null pointer. This is an example where there is a more complex mapping between C objects and Scheme objects. C's char* type is represented as one of two Scheme types depending on its value. This allows us us to distinguish between the C string (pointer) that points to the empty sequence of characters and the null pointer (which doesnt point anywhere).

— windows type: handle
— windows type: hbitmap
— windows type: hbrush
— windows type: hcursor
— windows type: hdc
— windows type: hicon
— windows type: hinstance
— windows type: hmenu
— windows type: hpalette
— windows type: hpen
— windows type: hrgn
— windows type: hwnd

Various kinds of Win32 handle. These names correspond to the same, but all uppercase, names in the Windows C language header files. Win32 API calls are the source of values of this type and the values are meaningless except as arguments to other Win32 API calls. Currently these values are represented as integers but we expect that Win32 handles will in future be represented by allocated Scheme objects (e.g. records) that will allow predicates (e.g. hmenu?) and sensible interlocking with the garbage collector to free the programmer of the current tedious allocation and deallocation of handles.

— windows type: resource-id

A Windows resource identifier is either a small integer or a string. In C, this distinction is possible because pointers look like larger integers, so a machine word representing a small integer can be distinguished from a machine word that is a pointer to the text of the name of the resource.