|
While it is possible to call a C/C++ DLL from
Smalltalk MT, sometimes we would like to be able to callback Smalltalk MT
from a C/C++ DLL or EXE. This enables us to share code in both
environment.
A Smalltalk MT application can be called back on the class side or the
instance side.
Let's deal with the simplest case first which is a callback on the class
side.
Class side callbacks
In C/C++, we create a standard function pointer
typedef BOOL (WINAPI* STMTFUNC)(DWORD);
This function prototype says that the STMT function will return a boolean
value and will be passed a single parameter.
We need to pass the address of the STMT method to the C/C++ program and
so let's create a C/C++ method to do that. In this case I am going to assume
that the C/C++ program is a DLL so here is the API.
INT WINAPI Setup(STMTFUNC renderFunction)
{
...code...
if(!renderFunction(someParameter))
OutputDebugString("Callback failed");
...code...
}
In the Smalltalk code, we create a class method in the category
.EXPORT (this is important
since it specified the calling convention for STMT. .EXPORT uses the WINAPI
calling convention)
CallbackFunction: aParameter
"Answer a boolean representing the
function success or failure"
aParameter < 5 ifTrue: [^FALSE]. "It
failed"
^TRUE
Notice that we must return C booleans TRUE (with a value of 1) or FALSE
(with a value of zero) since these will be returned directly to the C/C++
code.
The last piece we need is how to pass the function pointer to the C/C++
program.
The STMT method would look like
"Pass the function pointer to the C/C++ program"
WINAPI Setup: (MyClass methodAddressAt: #CallbackFunction:)
The methodAddressAt returns the address of the class method
CallbackFunction: and passes this to the C/C++ function Setup.
So now we execute this and the C/C++ program will call us back via the
class method.
Class side callback that forwards to the instance side
Quite often, it is inconvenient to have to use a class method. There is a
common technique to enable you to move from the class side to the instance
side.
typedef BOOL (WINAPI* STMTFUNC2)(DWORD, DWORD);
This time the callback function will have two parameters and the first
will be the Smalltalk instance address.
INT WINAPI Setup(DWORD instance, STMTFUNC renderFunction)
{
...code...
if(!renderFunction(instance,
someParameter)) OutputDebugString("Callback failed");
...code...
}
This time we are passed the Smalltalk instance address and we pass this
on as a parameter to the callback function.
CallbackFunction: instance with: aParameter
"Answer a boolean representing the
function success or failure"
^instance _asObject someMethod:
aParameter
The callback function turns the instance address back into an object
(_asObject) and sends this Smalltalk instance the method someMethod with the
parameter.
We can now setup the callback from a Smalltalk instance and pass the
calling objects address as the first parameter.
"Pass the function pointer to the C/C++ program"
WINAPI Setup: self basicAddress with: (MyClass methodAddressAt:
#CallbackFunction:)
Instance side callback
It is also possible to callback on the instance side directly. This is
how COM works. The instance side callback follow the Microsoft C++ calling
convention. This convention says that the first parameter must always be the
receiving objects address.
This time we would place the callback function in the .EXPORT category
on the instance side and use the same C/C++ sample that passes the
instance as the first parameter.
|