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

koffi.cdecl or koffi.func

(default)

This is the default convention, and the only one on other platforms

Stdcall

koffi.stdcall

__stdcall

This convention is used extensively within the Win32 API

Fastcall

koffi.fastcall

__fastcall

Rarely used, uses ECX and EDX for first two parameters

Thiscall

koffi.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)');