koffi 1.2.4 → 1.3.0-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. package/README.md +7 -489
  2. package/benchmark/CMakeLists.txt +13 -9
  3. package/benchmark/raylib_node_raylib.js +67 -0
  4. package/build/qemu/1.3.0-rc.1/koffi_darwin_arm64.tar.gz +0 -0
  5. package/build/qemu/1.3.0-rc.1/koffi_darwin_x64.tar.gz +0 -0
  6. package/build/qemu/1.3.0-rc.1/koffi_freebsd_arm64.tar.gz +0 -0
  7. package/build/qemu/1.3.0-rc.1/koffi_freebsd_ia32.tar.gz +0 -0
  8. package/build/qemu/1.3.0-rc.1/koffi_freebsd_x64.tar.gz +0 -0
  9. package/build/qemu/1.3.0-rc.1/koffi_linux_arm32hf.tar.gz +0 -0
  10. package/build/qemu/1.3.0-rc.1/koffi_linux_arm64.tar.gz +0 -0
  11. package/build/qemu/1.3.0-rc.1/koffi_linux_ia32.tar.gz +0 -0
  12. package/build/qemu/1.3.0-rc.1/koffi_linux_riscv64hf64.tar.gz +0 -0
  13. package/build/qemu/1.3.0-rc.1/koffi_linux_x64.tar.gz +0 -0
  14. package/build/qemu/1.3.0-rc.1/koffi_openbsd_ia32.tar.gz +0 -0
  15. package/build/qemu/1.3.0-rc.1/koffi_openbsd_x64.tar.gz +0 -0
  16. package/build/qemu/1.3.0-rc.1/koffi_win32_arm64.tar.gz +0 -0
  17. package/build/qemu/1.3.0-rc.1/koffi_win32_ia32.tar.gz +0 -0
  18. package/build/qemu/1.3.0-rc.1/koffi_win32_x64.tar.gz +0 -0
  19. package/doc/Makefile +20 -0
  20. package/doc/_static/bench_linux.png +0 -0
  21. package/doc/_static/bench_windows.png +0 -0
  22. package/doc/_static/custom.css +22 -0
  23. package/doc/benchmarks.md +113 -0
  24. package/doc/benchmarks.xlsx +0 -0
  25. package/doc/conf.py +54 -0
  26. package/doc/contribute.md +115 -0
  27. package/doc/dist/doctrees/benchmarks.doctree +0 -0
  28. package/doc/dist/doctrees/contribute.doctree +0 -0
  29. package/doc/dist/doctrees/environment.pickle +0 -0
  30. package/doc/dist/doctrees/functions.doctree +0 -0
  31. package/doc/dist/doctrees/index.doctree +0 -0
  32. package/doc/dist/doctrees/memory.doctree +0 -0
  33. package/doc/dist/doctrees/platforms.doctree +0 -0
  34. package/doc/dist/doctrees/start.doctree +0 -0
  35. package/doc/dist/doctrees/types.doctree +0 -0
  36. package/doc/dist/html/.buildinfo +4 -0
  37. package/doc/dist/html/_sources/benchmarks.md.txt +113 -0
  38. package/doc/dist/html/_sources/contribute.md.txt +115 -0
  39. package/doc/dist/html/_sources/functions.md.txt +224 -0
  40. package/doc/dist/html/_sources/index.rst.txt +33 -0
  41. package/doc/dist/html/_sources/memory.md.txt +29 -0
  42. package/doc/dist/html/_sources/platforms.md.txt +17 -0
  43. package/doc/dist/html/_sources/start.md.txt +89 -0
  44. package/doc/dist/html/_sources/types.md.txt +514 -0
  45. package/doc/dist/html/_static/_sphinx_javascript_frameworks_compat.js +134 -0
  46. package/doc/dist/html/_static/basic.css +932 -0
  47. package/doc/dist/html/_static/bench_linux.png +0 -0
  48. package/doc/dist/html/_static/bench_windows.png +0 -0
  49. package/doc/dist/html/_static/custom.css +22 -0
  50. package/doc/dist/html/_static/debug.css +69 -0
  51. package/doc/dist/html/_static/doctools.js +264 -0
  52. package/doc/dist/html/_static/documentation_options.js +14 -0
  53. package/doc/dist/html/_static/file.png +0 -0
  54. package/doc/dist/html/_static/jquery-3.6.0.js +10881 -0
  55. package/doc/dist/html/_static/jquery.js +2 -0
  56. package/doc/dist/html/_static/language_data.js +199 -0
  57. package/doc/dist/html/_static/minus.png +0 -0
  58. package/doc/dist/html/_static/plus.png +0 -0
  59. package/doc/dist/html/_static/pygments.css +252 -0
  60. package/doc/dist/html/_static/scripts/furo-extensions.js +0 -0
  61. package/doc/dist/html/_static/scripts/furo.js +3 -0
  62. package/doc/dist/html/_static/scripts/furo.js.LICENSE.txt +7 -0
  63. package/doc/dist/html/_static/scripts/furo.js.map +1 -0
  64. package/doc/dist/html/_static/searchtools.js +531 -0
  65. package/doc/dist/html/_static/skeleton.css +296 -0
  66. package/doc/dist/html/_static/styles/furo-extensions.css +2 -0
  67. package/doc/dist/html/_static/styles/furo-extensions.css.map +1 -0
  68. package/doc/dist/html/_static/styles/furo.css +2 -0
  69. package/doc/dist/html/_static/styles/furo.css.map +1 -0
  70. package/doc/dist/html/_static/underscore-1.13.1.js +2042 -0
  71. package/doc/dist/html/_static/underscore.js +6 -0
  72. package/doc/dist/html/benchmarks.html +547 -0
  73. package/doc/dist/html/contribute.html +382 -0
  74. package/doc/dist/html/functions.html +530 -0
  75. package/doc/dist/html/genindex.html +249 -0
  76. package/doc/dist/html/index.html +342 -0
  77. package/doc/dist/html/memory.html +337 -0
  78. package/doc/dist/html/objects.inv +0 -0
  79. package/doc/dist/html/platforms.html +332 -0
  80. package/doc/dist/html/search.html +257 -0
  81. package/doc/dist/html/searchindex.js +1 -0
  82. package/doc/dist/html/start.html +367 -0
  83. package/doc/dist/html/types.html +1001 -0
  84. package/doc/functions.md +224 -0
  85. package/doc/index.rst +33 -0
  86. package/doc/make.bat +35 -0
  87. package/doc/memory.md +29 -0
  88. package/doc/platforms.md +17 -0
  89. package/doc/start.md +89 -0
  90. package/doc/types.md +514 -0
  91. package/package.json +5 -2
  92. package/qemu/qemu.js +41 -27
  93. package/qemu/registry/machines.json +59 -79
  94. package/qemu/registry/sha256sum.txt +4 -4
  95. package/src/abi_arm32.cc +20 -48
  96. package/src/abi_arm64.cc +18 -46
  97. package/src/abi_arm64_fwd.S +5 -0
  98. package/src/abi_riscv64.cc +19 -47
  99. package/src/abi_x64_sysv.cc +18 -46
  100. package/src/abi_x64_win.cc +19 -47
  101. package/src/abi_x86.cc +21 -49
  102. package/src/call.cc +505 -242
  103. package/src/call.hh +14 -7
  104. package/src/ffi.cc +47 -26
  105. package/src/ffi.hh +1 -1
  106. package/src/parser.cc +2 -20
  107. package/src/util.cc +50 -11
  108. package/src/util.hh +2 -0
  109. package/test/misc.c +31 -0
  110. package/test/sync.js +41 -4
  111. package/benchmark/atoi_cc.cc +0 -59
  112. package/build/qemu/1.2.4/koffi_darwin_arm64.tar.gz +0 -0
  113. package/build/qemu/1.2.4/koffi_darwin_x64.tar.gz +0 -0
  114. package/build/qemu/1.2.4/koffi_freebsd_arm64.tar.gz +0 -0
  115. package/build/qemu/1.2.4/koffi_freebsd_ia32.tar.gz +0 -0
  116. package/build/qemu/1.2.4/koffi_freebsd_x64.tar.gz +0 -0
  117. package/build/qemu/1.2.4/koffi_linux_arm.tar.gz +0 -0
  118. package/build/qemu/1.2.4/koffi_linux_arm64.tar.gz +0 -0
  119. package/build/qemu/1.2.4/koffi_linux_ia32.tar.gz +0 -0
  120. package/build/qemu/1.2.4/koffi_linux_riscv64.tar.gz +0 -0
  121. package/build/qemu/1.2.4/koffi_linux_x64.tar.gz +0 -0
  122. package/build/qemu/1.2.4/koffi_openbsd_ia32.tar.gz +0 -0
  123. package/build/qemu/1.2.4/koffi_openbsd_x64.tar.gz +0 -0
  124. package/build/qemu/1.2.4/koffi_win32_arm64.tar.gz +0 -0
  125. package/build/qemu/1.2.4/koffi_win32_ia32.tar.gz +0 -0
  126. package/build/qemu/1.2.4/koffi_win32_x64.tar.gz +0 -0
@@ -0,0 +1,224 @@
1
+ # Function calls
2
+
3
+ ## Function definitions
4
+
5
+ To declare functions, start by loading the shared library with `koffi.load()`.
6
+
7
+ ```js
8
+ const koffi = require('koffi');
9
+ const lib = koffi.load('/path/to/shared/library'); // File extension depends on platforms: .so, .dll, .dylib, etc.
10
+ ```
11
+
12
+ You can use the returned object to load C functions from the library. Koffi supports two syntaxes:
13
+
14
+ - Classic syntax, inspired by node-ffi
15
+ - C-like prototypes
16
+
17
+ ### Classic syntax
18
+
19
+ 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.
20
+
21
+ ```js
22
+ const printf = lib.func('printf', 'int', ['string', '...']);
23
+ const atoi = lib.func('atoi', 'int', ['string']);
24
+ ```
25
+
26
+ Koffi automatically tries mangled names for non-standard x86 calling conventions. See the section [on standard calls](#synchronous-calls) for more information on this subject.
27
+
28
+ ### C-like prototypes
29
+
30
+ You can declare functions using simple C-like prototype strings, as shown below:
31
+
32
+ ```js
33
+ const printf = lib.func('int printf(const char *fmt, ...)');
34
+ const atoi = lib.func('int atoi(string)'); // The parameter name is not used by Koffi, and optional
35
+ ```
36
+
37
+ ## Synchronous calls
38
+
39
+ By default, calling a C function happens synchronously.
40
+
41
+ Most architectures only support one procedure call standard per process. The 32-bit x86 platform is an exception to this, and Koffi support several standards:
42
+
43
+ Convention | Classic form | Prototype form | Description
44
+ ------------- | ----------------------------- | -------------- | -------------------------------------------------------------------
45
+ **Cdecl** | `koffi.cdecl` or `koffi.func` | _(default)_ | This is the default convention, and the only one on other platforms
46
+ **Stdcall** | `koffi.stdcall` | __stdcall | This convention is used extensively within the Win32 API
47
+ **Fastcall** | `koffi.fastcall` | __fastcall | Rarely used, uses ECX and EDX for first two parameters
48
+ **Thiscall** | `koffi.thiscall` | __thiscall | Rarely used, uses ECX for first parameter
49
+
50
+ You can safely use these on non-x86 platforms, they are simply ignored.
51
+
52
+ Below you can find a small example showing how to use a non-default calling convention:
53
+
54
+ ```js
55
+ const koffi = require('koffi');
56
+ const lib = koffi.load('user32.dll');
57
+
58
+ // The following two declarations are equivalent, and use Stdcall
59
+ const MessageBoxA_1 = lib.stdcall('MessageBoxA', 'int', ['void *', 'string', 'string', 'uint']);
60
+ const MessageBoxA_2 = lib.func('int __stdcall MessageBoxA(void *hwnd, string text, string caption, uint type)');
61
+ ```
62
+
63
+ ## Asynchronous calls
64
+
65
+ You can issue asynchronous calls by calling the function through its async member. In this case, you need to provide a callback function as the last argument, with `(err, res)` parameters.
66
+
67
+ ```js
68
+ const koffi = require('koffi');
69
+ const lib = koffi.load('libc.so.6');
70
+
71
+ const atoi = lib.func('int atoi(const char *str)');
72
+
73
+ atoi.async('1257', (err, res) => {
74
+ console.log('Result:', res);
75
+ })
76
+ console.log('Hello World!');
77
+
78
+ // This program will print "Hello World!", and then "Result: 1257"
79
+ ```
80
+
81
+ You can easily convert this callback-style async function to a promise-based version with `util.promisify()` from the Node.js standard library.
82
+
83
+ Variadic functions cannot be called asynchronously.
84
+
85
+ ## Variadic functions
86
+
87
+ Variadic functions are declared with an ellipsis as the last argument.
88
+
89
+ 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.
90
+
91
+ ```js
92
+ const printf = lib.func('printf', 'int', ['string', '...']);
93
+
94
+ // The variadic arguments are: 6 (int), 8.5 (double), 'THE END' (const char *)
95
+ printf('Integer %d, double %g, string %s', 'int', 6, 'double', 8.5, 'string', 'THE END');
96
+ ```
97
+
98
+ On x86 platforms, only the Cdecl convention can be used for variadic functions.
99
+
100
+ ## Output parameters
101
+
102
+ By default, Koffi will only forward arguments from Javascript to C. However, many C functions use pointer arguments for output values, or input/output values.
103
+
104
+ For simplicy, and because Javascript only has value semantics for primitive types, Koffi can marshal out (or in/out) two types of parameters:
105
+
106
+ - [Structs](types.md#struct-types) (to/from JS objects)
107
+ - [Opaque handles](types.md#opaque-handles)
108
+
109
+ In order to change an argument from input-only to output or input/output, use the following functions:
110
+
111
+ - `koffi.out()` on a pointer, e.g. `koffi.out(koffi.pointer(timeval))` (where timeval is a struct type)
112
+ - `koffi.inout()` for dual input/output parameters
113
+
114
+ The same can be done when declaring a function with a C-like prototype string, with the MSDN-like type qualifiers:
115
+
116
+ - `_Out_` for output parameters
117
+ - `_Inout_` for dual input/output parameters
118
+
119
+ ### Struct example
120
+
121
+ This example calls the POSIX function `gettimeofday()`, and uses the prototype-like syntax.
122
+
123
+ ```js
124
+ const koffi = require('koffi');
125
+ const lib = koffi.load('libc.so.6');
126
+
127
+ const timeval = koffi.struct('timeval', {
128
+ tv_sec: 'unsigned int',
129
+ tv_usec: 'unsigned int'
130
+ });
131
+ const timezone = koffi.struct('timezone', {
132
+ tz_minuteswest: 'int',
133
+ tz_dsttime: 'int'
134
+ });
135
+
136
+ // The _Out_ qualifiers instruct Koffi to marshal out the values
137
+ const gettimeofday = lib.func('int gettimeofday(_Out_ timeval *tv, _Out_ timezone *tz)');
138
+
139
+ let tv = {};
140
+ gettimeofday(tv, null);
141
+
142
+ console.log(tv);
143
+ ```
144
+
145
+ ### Opaque handle example
146
+
147
+ This example opens an in-memory SQLite database, and uses the node-ffi-style function declaration syntax.
148
+
149
+ ```js
150
+ const koffi = require('koffi');
151
+ const lib = koffi.load('sqlite.so');
152
+
153
+ const sqlite3_db = koffi.handle('sqlite3_db');
154
+
155
+ // Use koffi.out() on a pointer to copy out (from C to JS) after the call
156
+ const sqlite3_open_v2 = lib.func('sqlite3_open_v2', 'int', ['string', koffi.out(koffi.pointer(sqlite3_db)), 'int', 'string']);
157
+
158
+ const SQLITE_OPEN_READWRITE = 0x2;
159
+ const SQLITE_OPEN_CREATE = 0x4;
160
+
161
+ let db = {};
162
+ if (sqlite3_open_v2(':memory:', db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, null) != 0)
163
+ throw new Error('Failed to open database');
164
+ sqlite3_close_v2(db);
165
+ ```
166
+
167
+ ## Javascript callbacks
168
+
169
+ ### Using callbacks
170
+
171
+ In order to pass a JS function to a C function expecting a callback, you must first create a callback type with the expected return type and parameters. The syntax is similar to the one used to load functions from a shared library.
172
+
173
+ ```js
174
+ const koffi = require('koffi');
175
+
176
+ // With the classic syntax, this callback expects an integer and returns nothing
177
+ const ExampleCallback = koffi.callback('ExampleCallback', 'void', ['int']);
178
+
179
+ // With the prototype parser, this callback expects a double and float, and returns the sum as a double
180
+ const AddDoubleFloat = koffi.callback('double AddDoubleFloat(double d, float f)');
181
+ ```
182
+
183
+ Once your callback type is declared, you can use them in struct definitions, or as function parameter and/or return type.
184
+
185
+ Here is a small example with the C part and the JS part.
186
+
187
+ ```c
188
+ #include <string.h>
189
+
190
+ int TransferToJS(const char *name, int age, int (*cb)(const char *str, int age))
191
+ {
192
+ char buf[64];
193
+ snprintf(buf, sizeof(buf), "Hello %s!", str);
194
+ return cb(buf, age);
195
+ }
196
+ ```
197
+
198
+ ```js
199
+ const koffi = require('koffi');
200
+
201
+ const TransferCallback = koffi.callback('int TransferCallback(const char *str, int age)');
202
+
203
+ const TransferToJS = lib.func('int TransferToJS(const char *str, int age, TransferCallback cb)');
204
+
205
+ let ret = TransferToJS('Niels', 27, (str, age) => {
206
+ console.log(str);
207
+ console.log('Your age is:', age);
208
+ return 42;
209
+ });
210
+ console.log(ret);
211
+
212
+ // This example prints:
213
+ // Hello Niels!
214
+ // Your age is: 27
215
+ // 42
216
+ ```
217
+
218
+ On x86 platforms, only Cdecl and Stdcall callbacks are supported.
219
+
220
+ ### Thread safety
221
+
222
+ The callback must be called from the main thread, or more precisely from the same thread as the V8 intepreter.
223
+
224
+ Calling the callback from another thread is undefined behavior, and will likely lead to a mess.
@@ -0,0 +1,33 @@
1
+ Koffi
2
+ =====
3
+
4
+ Overview
5
+ --------
6
+
7
+ Koffi is a **fast and easy-to-use C FFI module for Node.js**, featuring:
8
+
9
+ * Low-overhead and fast performance (see :ref:`Benchmarks`)
10
+ * Support for primitive and aggregate data types (structs and fixed-size arrays), both by reference (pointer) and by value
11
+ * Javascript functions can be used as C callbacks (since 1.2.0)
12
+ * Well-tested code base for :ref:`popular OS/architecture combinations<Supported platforms>`
13
+
14
+ Table of contents
15
+ -----------------
16
+
17
+ .. toctree::
18
+ :maxdepth: 2
19
+
20
+ platforms
21
+ start
22
+ types
23
+ functions
24
+ memory
25
+ benchmarks
26
+ contribute
27
+
28
+ License
29
+ -------
30
+
31
+ This program is free software: you can redistribute it and/or modify it under the terms of the **GNU Affero General Public License** as published by the Free Software Foundation, either **version 3 of the License**, or (at your option) any later version.
32
+
33
+ Find more information here: https://www.gnu.org/licenses/
@@ -0,0 +1,29 @@
1
+ # Memory usage
2
+
3
+ ## How it works
4
+
5
+ For synchronous/normal calls, Koffi uses two preallocated memory blocks:
6
+
7
+ - One to construct to assign the C stack, subsequently used by the platform-specific assembly code (1 MiB by default)
8
+ - One to allocate strings and big objects/structs (2 MiB by default)
9
+
10
+ Unless very big strings or objects (at least more than one page of memory) are used, no extra allocation ever happens during calls or callbacks.
11
+
12
+ The size (in bytes) of these preallocated blocks can be changed. Use `koffi.config()` to get an object with the settings, and `koffi.config(obj)` to apply new settings.
13
+
14
+ ```js
15
+ let config = koffi.config();
16
+ console.log(config);
17
+ ```
18
+
19
+ The same is true for asynchronous calls. When an asynchronous call is made, Koffi will allocate new blocks unless there is an unused (resident) set of blocks still available. Once the asynchronous call is finished, these blocks are freed if there are more than `resident_async_pools` sets of blocks left around.
20
+
21
+ ## Default settings
22
+
23
+ Setting | Default | Description
24
+ -------------------- | ------- | -----------------------------------------------
25
+ sync_stack_size | 1 MiB | Stack size for synchronous calls
26
+ sync_heap_size | 2 MiB | Heap size for synchronous calls
27
+ async_stack_size | 512 kiB | Stack size for asynchronous calls
28
+ async_heap_size | 1 MiB | Heap size for asynchronous calls
29
+ resident_async_pools | 2 | Number of resident pools for asynchronous calls
@@ -0,0 +1,17 @@
1
+ # Supported platforms
2
+
3
+ The following combinations of OS and architectures __are officially supported and tested__ at the moment:
4
+
5
+ ISA / OS | Windows | Linux | macOS | FreeBSD | OpenBSD
6
+ ------------------ | ----------- | -------- | ----------- | ----------- | --------
7
+ x86 (IA32) [^1] | ✅ Yes | ✅ Yes | ⬜️ *N/A* | ✅ Yes | ✅ Yes
8
+ x86_64 (AMD64) | ✅ Yes | ✅ Yes | ✅ Yes | ✅ Yes | ✅ Yes
9
+ ARM32 LE [^2] | ⬜️ *N/A* | ✅ Yes | ⬜️ *N/A* | 🟨 Probably | 🟨 Probably
10
+ ARM64 (AArch64) LE | ✅ Yes | ✅ Yes | ✅ Yes | ✅ Yes | 🟨 Probably
11
+ RISC-V 64 [^3] | ⬜️ *N/A* | ✅ Yes | ⬜️ *N/A* | 🟨 Probably | 🟨 Probably
12
+
13
+ For all fully supported platforms (green check marks), a prebuilt binary is included in the NPM package which means you can install Koffi without a C++ compiler.
14
+
15
+ [^1]: The following call conventions are supported for forward calls: cdecl, stdcall, MS fastcall, thiscall. Only cdecl and stdcall can be used for C to JS callbacks.
16
+ [^2]: The prebuilt binary uses the hard float ABI and expects a VFP coprocessor. Build from source to use Koffi with a different ABI (softfp, soft).
17
+ [^3]: The prebuilt binary uses the LP64D (double-precision float) ABI. The LP64 ABI is supported in theory if you build Koffi from source (untested), the LP64F ABI is not supported.
@@ -0,0 +1,89 @@
1
+ # Quick start
2
+
3
+ You can install Koffi with npm:
4
+
5
+ ```sh
6
+ npm install koffi
7
+ ```
8
+
9
+ Once you have installed Koffi, you can start by loading it this way:
10
+
11
+ ```js
12
+ const koffi = require('koffi');
13
+ ```
14
+
15
+ Below you can find three examples:
16
+
17
+ * The first one runs on Linux. The functions are declared with the C-like prototype language.
18
+ * The second one runs on Windows, and uses the node-ffi like syntax to declare functions.
19
+
20
+ ## Small Linux example
21
+
22
+ This is a small example for Linux systems, which uses `gettimeofday()` and `printf()` to print the current time and the timezone.
23
+
24
+ It illustrates the use of output parameters.
25
+
26
+ ```js
27
+ const koffi = require('koffi');
28
+
29
+ // Load the shared library
30
+ const lib = koffi.load('libc.so.6');
31
+
32
+ // Declare struct types
33
+ const timeval = koffi.struct('timeval', {
34
+ tv_sec: 'unsigned int',
35
+ tv_usec: 'unsigned int'
36
+ });
37
+ const timezone = koffi.struct('timezone', {
38
+ tz_minuteswest: 'int',
39
+ tz_dsttime: 'int'
40
+ });
41
+ const time_t = koffi.struct('time_t', { value: 'int64_t' });
42
+ const tm = koffi.struct('tm', {
43
+ tm_sec: 'int',
44
+ tm_min: 'int',
45
+ tm_hour: 'int',
46
+ tm_mday: 'int',
47
+ tm_mon: 'int',
48
+ tm_year: 'int',
49
+ tm_wday: 'int',
50
+ tm_yday: 'int',
51
+ tm_isdst: 'int'
52
+ });
53
+
54
+ // Find functions
55
+ const gettimeofday = lib.func('int gettimeofday(_Out_ timeval *tv, _Out_ timezone *tz)');
56
+ const localtime_r = lib.func('tm *localtime_r(const time_t *timeval, _Out_ tm *result)');
57
+ const printf = lib.func('int printf(const char *format, ...)');
58
+
59
+ // Get local time
60
+ let tv = {};
61
+ let now = {};
62
+ gettimeofday(tv, null);
63
+ localtime_r({ value: tv.tv_sec }, now);
64
+
65
+ // And format it with printf (variadic function)
66
+ printf('Hello World!\n');
67
+ printf('Local time: %02d:%02d:%02d\n', 'int', now.tm_hour, 'int', now.tm_min, 'int', now.tm_sec);
68
+ ```
69
+
70
+ ## Small Windows example
71
+
72
+ This is a small example targeting the Win32 API, using `MessageBox()` to show a Hello message to the user.
73
+
74
+ It illustrates the use of the x86 stdcall calling convention.
75
+
76
+ ```js
77
+ const koffi = require('koffi');
78
+
79
+ // Load the shared library
80
+ const lib = koffi.load('user32.dll');
81
+
82
+ // Declare constants
83
+ const MB_ICONINFORMATION = 0x40;
84
+
85
+ // Find functions
86
+ const MessageBoxA = lib.stdcall('MessageBoxA', 'int', ['void *', 'string', 'string', 'uint']);
87
+
88
+ MessageBoxA(null, 'Hello', 'Foobar', MB_ICONINFORMATION);
89
+ ```