To use the C callout mechanism, you first need to inform Smalltalk about
the C functions that you wish to call. You currently need to do this in
two places: 1) you need to establish the mapping between your C
function's address and the name that you wish to refer to it by, and 2)
define that function along with how the argument objects should be
mapped to C data types to the Smalltalk interpreter. As an example, let
us use the pre-defined (to gnu Smalltalk) functions of
First, the mapping between these functions and string names for the functions needs to be established in your module. If you are writing an external Smalltalk module (which can look at Smalltalk objects and manipulate them), see Linking your libraries to the virtual machine; if you are using function from a dynamically loaded library, see Dynamic loading.
Second, we need to define a method that will invoke these C functions and describe its arguments to the Smalltalk runtime system. Such a method is defined with a primitive-like syntax, similar to the following example (taken from kernel/CFuncs.st)
system: aString <cCall: 'system' returning: #int args: #(#string)> getenv: aString <cCall: 'getenv' returning: #string args: #(#string)>
These methods were defined on class
that we would invoke it thus:
Smalltalk system: 'lpr README' !
However, there is no special significance to which class receives the method; it could have just as well been Float, but it might look kind of strange to see:
1701.0 system: 'mail firstname.lastname@example.org' !
The various keyword arguments are described below.
system. This name must be exactly the same as the string passed to
The name of the method does not have to match the name of the C function;
we could have just as easily defined the selector to be
fooFoo'; it's just good practice to define the method with a similar
name and the argument names to reflect the data types that should be
selfreturned from Smalltalk)
wchar_t *), converted to a UnicodeString
wchar_t *), converted to a UnicodeString and then freed
#narrowbefore being returned: an example of this feature is given in the experimental Gtk+ bindings.
args: #(string int int)
The following argument types are supported; see above for details.
char, which is promoted to
char, which is promoted to
char *, the contents are expected to be overwritten with a new C string, and the object that was passed becomes the new string on return
wchar_t *, the contents are expected to be overwritten with a new C wide string, and the object that was passed becomes the new string on return
char *, even though may contain NUL's
Any class with non-pointer indexed instance variables can be passed as
#cObject, and GNU Smalltalk will pass the address of the first indexed
instance variable. This however should never be done for functions that
allocate objects, call back into Smalltalk code or otherwise may cause
a garbage collection: after a GC, pointers passed as
#cObject may be
invalidated. In this case, it is safer to pass every object as
#smalltalk, or to only pass
CObjects that were returned
by a C function previously.
#cObject can be used for function pointers. These are
CCallable or one of its subclasses. See Smalltalk callbacks for more information on how to create function pointers for
void **. The
CObjectis modified on output to reflect the value stored into the passed object.
variadicis used, or passed as a raw object pointer for
selfis used or passing the raw object pointer for
selfSmalltalk. Parameters passed this way don't map to the message's arguments, instead they map to the message's receiver.
Table of parameter conversions:
|Declared param type||Object type||C parameter type used
|boolean||Boolean (True, False)||int
|cObject||ByteArray, etc.||void *
|char||Boolean (True, False)||int
|char||Character||int (C promotion rule)
|double||Float||double (C promotion)
|int||Boolean (True, False)||int
|uInt||Boolean (True, False)||unsigned int
|long||Boolean (True, False)||long
|uLong||Boolean (True, False)||unsigned long
|unknown, self||Boolean (True, False)||int
|unknown, self||ByteArray||char *
|unknown, self||CObject||void *
|unknown, self||String||char *
|unknown, self||Symbol||char *
|unknown, self||anything else||OOP
|variadic||Array||each element is passed according to "unknown"
|variadicSmalltalk||Array||each element is passed as an OOP
When your call-out returns
#void, depending on your
application you might consider using asynchronous
call-outs. These are call-outs that do not suspend the process
that initiated them, so the process might be scheduled again,
executing the code that follows the call-out, during the execution
of the call-out itself. This is particularly handy when writing
event loops (the most common place where you call back into Smalltalk)
because then you can handle events that arrive during the
handling of an outer event before the outer event's processing
has ended. Depending on your application this might be correct or
not, of course. In the future, asynchronous call-outs might be
started into a separate thread.
An asynchronous call-out is defined using an alternate primitive-like
asyncCCall:args:. Note that the returned value parameter
is missing because an asynchronous call-out always returns