To provide the capability of calling Smalltalk from outside of Smalltalk. This mechanism allows for Smalltalk to execute a function outside of Smalltalk, such as an API, which itself requires some Smalltalk processing before returning.
In the Smalltalk development environment, the callback
facility is used to enumerate the system supported fonts. This
example will be used in discussing the programmer interface.
First, the API must be defined. In the case of fonts, this is in the method
GDIDLL>>enumFonts:lpFacename:lpFontFunc:lpData:
enumFonts: hDC lpFacename: lpFacename lpFontFunc: lpEnumFunc lpData: lpData
<api: enumFonts ushort ulong ulong ulong short>
^self invalidArgument
lpEnumFunc is the FARPROC procedure-instance address of the callback function. In Smalltalk it is a long pointer to the code in the virtual machine which identifies the Smalltalk call back message processing. This is obtained by registering a message with the CallBack class as explained in detail below.
Now the necessary Smalltalk message processing must be registered with the class CallBack. Look at the method Font class>>allFonts, which contains code which looks like this:
| aCallBack aMessage faceList allFonts font |
aMessage := Message new.
aMessage receiver: Font.
aMessage selector: #enumFaces:lpTextMetrics:nFontType:lpData:.
aCallBack := CallBack
registerMessage: aMessage
parameterTypes:#(ulong ulong short ulong)
returnType: #short
callingConvention:#pascal.
"some other code appears in here..."
GDILibrary
enumFonts: graphicsMedium deviceContext
lpFacename: 0
lpFontFunc: aCallBack asParameter
lpData: 0.
aCallBack release.
"the rest of the method appears here..."
The message
CallBack
registerMessage: stMessage
parameterTypes: aParameterTypeArray
returnType: aReturnType
callingConvention: aCcType
registers the message processing with the CallBack class. The arguments are as follows: stMessage is the actual Smalltalk message to be performed when the call back is invoked. For the EnumFont API this would be the actual call back function, a Smalltalk message:
aMessage := Message new.
aMessage receiver: Font.
aMessage selector: #enumFaces:lpTextMetrics:nFontType:lpData:.
- aParameterTypeArray is an array of argument types. This collection
indicates how to convert the procedure parameter into a Smalltalk object.
Currently, possible parameter types are:
#short
#ushort
#long
#ulong
#handle
Currently, #float and #double parameter types are not supported. For the EnumFont API this would be an array of argument conversation selectors for the call back function:
#(ulong ulong short ulong)
- aReturnType is the type that is expected to be returned from the callback function. For EnumFont API this would be #short.
- aCcType is the type of calling convention used for passing the procedure parameters, such as standard C or Pascal. This is to enable the virtual-machine to correctly handle the stacked parameters. Currently, possible calling convention types are:
#pascal
#c
For the EnumWindows API this would be #pascal.
This creates an instance of CallBack and returns a long pointer. This is the actual FARPROC procedure-instance address of the callback function that is passed to the API requiring the call back capability; in the case of fonts, this is the lpEnumFunc parameter to the API.
Usage notes:
Remember to send a "asParameter" message to the CallBack object before passing it to the API.
When the CallBack object is no longer needed is should be released using CallBack>>release method.
A CallBack object needs to be recreated for each Smalltalk session.