« MBS Xojo Plugins, ver… | Home | Xojo's seventh birthd… »

Dynamic Declare for Xojo


For MBS Xojo Plugins in version 20.3 we include a new set of classes to do load C libraries and call functions there. Similar to the declare commands in Xojo, but much more dynamic and with additional features:

Libraries

Our new DeclareLibraryMBS class allows you to load a library file. On MacOS you load a dylib file, on Windows a DLL file and on Linux a shared object file with so file extension.

Just pass the file path (can be relative) or the folder item for the library file to the constructor for DeclareLibraryMBS. Then you can check with SymbolNames function the array of exported functions defined in the library. Once you picked a function name, you can use Symbol function to query the function pointer for an exported function.

Functions

The new DeclareFunctionMBS class allows you to define a callable function as an object, similar to the built-in delegates in Xojo. You pass in to the constructor the function pointer you got via Symbol function before. And you pass the function signature to define the parameters and return values. For those we have kType* constants for you where you can add them together as a string. The types include things like "i" for an integer parameter or "p" for a pointer. The signature must match exactly the parameters of the C function with parameters in brackets and the return value attached to it. If the signature is wrong, the call later will fail and most likely crash the application.

Let's check an example:

bool test(int i, double d, const char* test)

This gives a signature "(idZ)B" with bool as result and int, double and a C string as parameter.

Once you have the function object, you can set parameters. We allow you to use ParameterInteger() and other setter/getter functions to pass in parameters directly as integer, pointer, boolean, single, double or string. We also allow to set/get the values as variant using ParameterValue(). If you need to set all parameters, you can use SetParameters method to pass values directly or as dictionary.

To call the C function, please call Invoke method. There we also allow you to pass parameters directly. The result is converted to a variant to handle all the possible data types.

Callbacks

Sometimes you may need to get a callback from a library and for this we have the DeclareCallBackMBS class. For the constructor you pass the signature for the function you need to pass to the delegate. A dynamic function stub is created, which accepts the given parameters, puts them in variables and passes them as parameters to the Callback event as variants. You can return a value, which then is returned as result of the function. Use the FunctionPtr property to get the ptr to the callback function.

For callbacks arriving on a different thread, we have a special handling. We can forward the call to the main thread for all platforms. For MacOS we can in addition do this asynchronously to not block the calling thread while we wait for main thread to process the request. When a call is forwarded to another thread, you may need to copy or retain object references. To solve this you can mark parameters to be Strings, NSObject or CFObject references. If you for example declare second parameter to be a NSObject, you can set ParameterNSRetain(1) = true. The callback function will retain it, so the object is staying alive while the call is performed and released later.

Constants

The table for the types to use for parameters and return value:

TypeNameDescription
vvoidnothing
BBOOLBoolean value
ccharsigned 8 bit value
Cunsigned charunsigned 8 bit value
sshortsigned 16 bit value
Sunsigned shortunsigned 16 bit value
iintsigned 32 bit value
Iunsigned intunsigned 32 bit value
jlongfor Windows 32-bit value, for MacOS and Linux 64-bit value
Junsigned longfor Windows 32-bit value, for MacOS and Linux 64-bit value
llong longsigned 64 bit value
Lunsigned long longunsigned 64 bit value
ffloatfloating point number in 32-bit size
ddoublefloating point number in 64-bit size
ppointerpointer in 32 or 64-bit.
ZC StringC style string with zero byte as end.

The prefixes you can put before all parameters to define the calling conventions:

PrefixNameDescription
DefaultNormal C function without prefix
_eEllipsisC function taking variable arguments
_sstdcallstandard calling convention
_ffastcall GNUFastcall convention as used in GNU compilers
_Ffastcall MicrosoftFastcall convention as used in Microsoft compilers
_+thiscall MicrosoftThiscall convention as used in Microsoft compilers

Example

Here is a simple example using libz and the zlibVersion function. On MacOS the library is installed by default in "/usr/lib/libz.1.dylib". The function returns a string and takes no parameters. Calling convention is default C one, so no prefix. The signature is just "()Z" as there are no parameters and the result is a C string. We can then invoke the function and the plugin will take the returned C String and return it as a variant, where we can get the string from:

Dim d As New DeclareLibraryMBS("/usr/lib/libz.1.dylib") Dim p As ptr = d.Symbol("zlibVersion") Dim f As New DeclareFunctionMBS("()Z", p) Dim n As String = f.Invoke MsgBox "zlibVersion: "+n

Please do not hesitate to contact us with your questions.

The biggest plugin in space...
02 06 20 - 11:36