Library functions#
Loading libraries#
To declare functions, start by loading the shared library with koffi.load(filename)
.
1const koffi = require('koffi');
2const lib = koffi.load('/path/to/shared/library'); // File extension depends on platforms: .so, .dll, .dylib, etc.
This library will be automatically unloaded once all references to it (including all the functions that use it, as described below).
Starting with Koffi 2.3.20, you can explicitly unload a library by calling lib.unload()
. Any attempt to find or call a function from this library after unloading it will crash.
Note
On some platforms (such as with the musl C library on Linux), shared libraries cannot be unloaded, so the library will remain loaded and memory mapped after the call to lib.unload()
.
Function definitions#
Definition syntax#
Use the object returned by koffi.load()
to load C functions from the library. To do so, you can use two syntaxes:
The classic syntax, inspired by node-ffi
C-like prototypes
Classic syntax#
To declare a function, you need to specify its non-mangled name, its return type, and its parameters. Use an ellipsis as the last parameter for variadic functions.
1const printf = lib.func('printf', 'int', ['str', '...']);
2const atoi = lib.func('atoi', 'int', ['str']);
Koffi automatically tries mangled names for non-standard x86 calling conventions. See the section on calling conventions for more information on this subject.
C-like prototypes#
If you prefer, you can declare functions using simple C-like prototype strings, as shown below:
1const printf = lib.func('int printf(const char *fmt, ...)');
2const atoi = lib.func('int atoi(str)'); // The parameter name is not used by Koffi, and optional
You can use ()
or (void)
for functions that take no argument.
Variadic functions#
Variadic functions are declared with an ellipsis as the last argument.
In order to call a variadic function, you must provide two Javascript arguments for each additional C parameter, the first one is the expected type and the second one is the value.
1const printf = lib.func('printf', 'int', ['str', '...']);
2
3// The variadic arguments are: 6 (int), 8.5 (double), 'THE END' (const char *)
4printf('Integer %d, double %g, str %s', 'int', 6, 'double', 8.5, 'str', 'THE END');
On x86 platforms, only the Cdecl convention can be used for variadic functions.
Calling conventions#
By default, calling a C function happens synchronously.
Most architectures only support one procedure call standard per process. The 32-bit x86 platform is an exception to this, and Koffi supports several x86 conventions:
Convention |
Classic form |
Prototype form |
Description |
---|---|---|---|
Cdecl |
|
(default) |
This is the default convention, and the only one on other platforms |
Stdcall |
|
__stdcall |
This convention is used extensively within the Win32 API |
Fastcall |
|
__fastcall |
Rarely used, uses ECX and EDX for first two parameters |
Thiscall |
|
__thiscall |
Rarely used, uses ECX for first parameter |
You can safely use these on non-x86 platforms, they are simply ignored.
Below you can find a small example showing how to use a non-default calling convention, with the two syntaxes:
1const koffi = require('koffi');
2const lib = koffi.load('user32.dll');
3
4// The following two declarations are equivalent, and use stdcall on x86 (and the default ABI on other platforms)
5const MessageBoxA_1 = lib.stdcall('MessageBoxA', 'int', ['void *', 'str', 'str', 'uint']);
6const MessageBoxA_2 = lib.func('int __stdcall MessageBoxA(void *hwnd, str text, str caption, uint type)');