Accessing functions
To call an external function from a script, you must first create an instance of the PlatformFunction class.
Creating functions manually
You can build up the platform function manually as follows:
| drawGraph |
drawGraph := PlatformFunction
language: 'c'
function: 'drawGraph'
library: 'CGRAPH'
parameterTypes: #(uint32 uint32 pointer)
returnType: #void.
Note:
The function name (drawGraph) is usually case-sensitive depending on the options you use when creating the DLL.
For more detailed information on parameter and return types, such as uint32 and pointer, refer to Programmer Reference.
The following table shows the mapping between the PlatformFunction calling convention and the platform-specific C compiler calling convention.
| | |
'c' | __stdcall | (none) |
'cdecl' | __cdecl | NA |
'thisCall' | __thiscall | NA |
Using the parser to create functions
Similarly, the following script segment uses the C language parser to build up the platform function automatically:
| drawGraph |
drawGraph :=
((AbtCLangParser parseFile: 'cgraph.h')
platformFunctions: 'cgraph.dll')
at: 'drawGraph' asSmalltalkGlobalIdentifier.
Similarly, you can use AbtCOBOLLangParser for COBOL.
Although this method might be easier for you, keep in mind that creating the platform function manually is generally faster because no parsing is necessary. In either case, you should design your scripts so that the platform function is only created once initially and not every time it is called
The parser tries to find the entry point in the DLL with the function name exactly as it appears in the parsed file, drawGraph in this example. If you create your DLL without options that maintain case-sensitivity, this automated technique will not work. For example, if cgraph.mak in this example had not used the /NOI link option to maintain case-sensitivity, the entry point in the DLL would have been DRAWGRAPH, which would not have been found. Use the manual technique if the case of the entry points in your DLL does not match the case of the function names in the file you are parsing.
Calling functions
After you have created the platform function, you can easily call it as follows:
drawGraph callWith: (ps asInteger)
with: 8
with: (pointArray abtAsExternalPassedPointer).
where ps is a presentation space handle and pointArray is the array of points as defined in the previous section.
Handling errors
When using platform functions, the most common errors are that the dynamic link library cannot be loaded or that the function you are calling does not exist. You can perform an error check on the drawGraph platform function, for example, as follows:
(drawGraph abtValidAddress) ifFalse:
^CwMessagePrompter errorMessage:
'The function was not created successfully.'].
Other errors resulting from incorrect parameters should be handled by the function being called.
For Windows:
The following code gives a description of Windows error codes:
| buffer |
buffer := String new: 255.
( PlatformFunctions at: 'FormatMessage' )
callWith: 4096 "FORMAT_MESSAGE_FROM_SYSTEM"
with: nil "No message source"
with: 4 "Error number here"
with: 0 "Language Identifier"
with: buffer "Message Buffer"
with: 255 "Message Buffer Maximum Size"
with: nil. "Message Inserts"
^ buffer trimNull
Last modified date: 07/23/2020