### Install Koffi with npm Source: https://koffi.dev/start Use this command to install Koffi. This is the first step before loading it in your project. ```bash npm install koffi ``` -------------------------------- ### Linux Example: Get and Print Current Time Source: https://koffi.dev/start This example for Linux systems uses C-like prototypes to interact with libc functions like gettimeofday, localtime_r, and printf. It demonstrates the use of output parameters and variadic functions. ```javascript import koffi from 'koffi'; // CJS: const koffi = require('koffi'); // Load the shared library const lib = koffi.load('libc.so.6'); // Declare struct types const timeval = koffi.struct('timeval', { tv_sec: 'unsigned int', tv_usec: 'unsigned int' }); const timezone = koffi.struct('timezone', { tz_minuteswest: 'int', tz_dsttime: 'int' }); const time_t = koffi.struct('time_t', { value: 'int64_t' }); const tm = koffi.struct('tm', { tm_sec: 'int', tm_min: 'int', tm_hour: 'int', tmay: 'int', tm_mon: 'int', tm_year: 'int', tm_wday: 'int', tm_yday: 'int', tm_isdst: 'int' }); // Find functions const gettimeofday = lib.func('int gettimeofday(_Out_ timeval *tv, _Out_ timezone *tz)'); const localtime_r = lib.func('tm *localtime_r(const time_t *timeval, _Out_ tm *result)'); const printf = lib.func('int printf(const char *format, ...)'); // Get local time let tv = {}; let now = {}; gettimeofday(tv, null); llocaltime_r({ value: tv.tv_sec }, now); // And format it with printf (variadic function) printf('Hello World!\n'); printf('Local time: %02d:%02d:%02d\n', 'int', now.tm_hour, 'int', now.tm_min, 'int', now.tm_sec); ``` -------------------------------- ### Download and Extract QEMU Machine Source: https://koffi.dev/contribute Download and extract pre-built QEMU machine images for cross-platform testing. This example downloads the Windows x64 machine. ```bash cd tools/cross/ wget -q -O- https://download.koromix.dev/qemu/qemu_windows_x64.tar.zst | zstd -d | tar xv ``` -------------------------------- ### Build Cross-Platform Test Machines Source: https://koffi.dev/contribute Create virtual machine environments for testing on different architectures. This example shows how to build the Debian ARM64 machine. ```bash cd tools/cross/build ./debian_arm64/build.sh ``` -------------------------------- ### Windows Example: MessageBox with stdcall and UTF-8/UTF-16 Source: https://koffi.dev/start This example for Windows targets the Win32 API, using MessageBoxA and MessageBoxW. It demonstrates the x86 stdcall calling convention and the handling of both UTF-8 and UTF-16 string arguments. ```javascript import koffi from 'koffi'; // CJS: const koffi = require('koffi'); // Load the shared library const lib = koffi.load('user32.dll'); // Declare constants const MB_OK = 0x0; const MB_YESNO = 0x4; const MB_ICONQUESTION = 0x20; const MB_ICONINFORMATION = 0x40; const IDOK = 1; const IDYES = 6; const IDNO = 7; // Find functions const MessageBoxA = lib.func('__stdcall', 'MessageBoxA', 'int', ['void *', 'str', 'str', 'uint']); const MessageBoxW = lib.func('__stdcall', 'MessageBoxW', 'int', ['void *', 'str16', 'str16', 'uint']); let ret = MessageBoxA(null, 'Do you want another message box?', 'Koffi', MB_YESNO | MB_ICONQUESTION); if (ret == IDYES) MessageBoxW(null, 'Hello World!', 'Koffi', MB_ICONINFORMATION); ``` -------------------------------- ### Initialize Electron App with Webpack Template Source: https://koffi.dev/packaging Command to initialize a new Electron application using Electron Forge with the webpack template. This setup should work with Koffi. ```bash npm init electron-app@latest my-app -- --template=webpack ``` -------------------------------- ### Opaque Type Example Source: https://koffi.dev/input Illustrates the basic structure and usage of an opaque type, including its definition and a typical `finally` block for resource management. ```c } finally { ConcatFree(c); } ``` -------------------------------- ### Load Koffi in your project Source: https://koffi.dev/start Import Koffi into your project using either CommonJS or ES6 module syntax. Ensure Koffi is installed first. ```javascript // CommonJS syntax const koffi = require('koffi'); ``` ```javascript // ES6 modules import koffi from 'koffi'; ``` -------------------------------- ### Get Machine Info Source: https://koffi.dev/contribute Retrieve connection details for VNC or SPICE servers running on test machines. This is useful for connecting with external viewers. ```bash node tools/brew.js info debian_x64 ``` -------------------------------- ### Transient Callback Example Source: https://koffi.dev/callbacks This example demonstrates a transient callback used within a C function that expects it to be called only during its execution. The JavaScript callback is defined using `koffi.proto()` and then passed to the C function. ```c #include int TransferToJS(const char *name, int age, int (*cb)(const char *str, int age)) { char buf[64]; snprintf(buf, sizeof(buf), "Hello %s!", str); return cb(buf, age); } ``` ```javascript import koffi from 'koffi'; // CJS: const koffi = require('koffi'); const lib = koffi.load('./callbacks.so'); // Fake path const TransferCallback = koffi.proto('int TransferCallback(const char *str, int age)'); const TransferToJS = lib.func('TransferToJS', 'int', ['str', 'int', koffi.pointer(TransferCallback)]); let ret = TransferToJS('Niels', 27, (str, age) => { console.log(str); console.log('Your age is:', age); return 42; }); console.log(ret); // This example prints: // Hello Niels! // Your age is: 27 // 42 ``` -------------------------------- ### Win32 SendInput Example Source: https://koffi.dev/unions Demonstrates using Koffi to interact with the Win32 API, specifically the `SendInput` function, to simulate keyboard events for the Win+D shortcut. Requires loading 'user32.dll' and defining necessary structures and constants. ```javascript import koffi from 'koffi'; // CJS: const koffi = require('koffi'); // Win32 type and functions const user32 = koffi.load('user32.dll'); const INPUT_MOUSE = 0; const INPUT_KEYBOARD = 1; const INPUT_HARDWARE = 2; const KEYEVENTF_KEYUP = 0x2; const KEYEVENTF_SCANCODE = 0x8; const VK_LWIN = 0x5B; const VK_D = 0x44; const MOUSEINPUT = koffi.struct('MOUSEINPUT', { dx: 'long', dy: 'long', mouseData: 'uint32_t', dwFlags: 'uint32_t', time: 'uint32_t', dwExtraInfo: 'uintptr_t' }); const KEYBDINPUT = koffi.struct('KEYBDINPUT', { wVk: 'uint16_t', wScan: 'uint16_t', dwFlags: 'uint32_t', time: 'uint32_t', dwExtraInfo: 'uintptr_t' }); const HARDWAREINPUT = koffi.struct('HARDWAREINPUT', { uMsg: 'uint32_t', wParamL: 'uint16_t', wParamH: 'uint16_t' }); const INPUT = koffi.struct('INPUT', { type: 'uint32_t', u: koffi.union({ mi: MOUSEINPUT, ki: KEYBDINPUT, hi: HARDWAREINPUT }) }); const SendInput = user32.func('unsigned int __stdcall SendInput(unsigned int cInputs, INPUT *pInputs, int cbSize)'); // Show/hide desktop with Win+D shortcut let events = [ make_keyboard_event(VK_LWIN, true), make_keyboard_event(VK_D, true), make_keyboard_event(VK_D, false), make_keyboard_event(VK_LWIN, false) ]; SendInput(events.length, events, koffi.sizeof(INPUT)); // Utility function make_keyboard_event(vk, down) { let event = { type: INPUT_KEYBOARD, u: { ki: { wVk: vk, wScan: 0, dwFlags: down ? 0 : KEYEVENTF_KEYUP, time: 0, dwExtraInfo: 0 } } }; return event; } ``` -------------------------------- ### Opaque Pointers: HANDLE Example Source: https://koffi.dev/pointers Illustrates how to define and use opaque pointers in Koffi, similar to Win32 API handles. `koffi.pointer` and `koffi.opaque` are used to create a named opaque type. ```APIDOC ## Opaque Pointers: HANDLE Example ### Description This example demonstrates the creation and usage of opaque pointers in Koffi, which are analogous to handles in C libraries like the Win32 API. It defines a `HANDLE` type using `koffi.pointer` and `koffi.opaque`. ### Method ```javascript const HANDLE = koffi.pointer('HANDLE', koffi.opaque()); // Example usage with hypothetical functions: // const GetHandleInformation = lib.func('bool __stdcall GetHandleInformation(HANDLE h, _Out_ uint32_t *flags)'); // const CloseHandle = lib.func('bool __stdcall CloseHandle(HANDLE h)'); // Koffi uses BigInt numbers to represent opaque pointers. ``` ``` -------------------------------- ### Get POSIX Struct Output (gettimeofday) Source: https://koffi.dev/output Demonstrates calling the POSIX `gettimeofday` function and retrieving struct output using prototype-like syntax with `_Out_` qualifiers. ```javascript import koffi from 'koffi'; // CJS: const koffi = require('koffi'); const lib = koffi.load('libc.so.6'); const timeval = koffi.struct('timeval', { tv_sec: 'unsigned int', tv_usec: 'unsigned int' }); const timezone = koffi.struct('timezone', { tz_minuteswest: 'int', tz_dsttime: 'int' }); // The _Out_ qualifiers instruct Koffi to marshal out the values const gettimeofday = lib.func('int gettimeofday(_Out_ timeval *tv, _Out_ timezone *tz)'); let tv = {}; gettimeofday(tv, null); console.log(tv); ``` -------------------------------- ### Clone Koffi Repository Source: https://koffi.dev/contribute Clone the main repository to start development. The actual source code for Koffi is located in a subdirectory within this monorepo. ```bash git clone https://codeberg.org/Koromix/rygel cd rygel ``` -------------------------------- ### Write to File using mmaped Memory with koffi.view() Source: https://koffi.dev/pointers This example demonstrates writing a string to a file by mapping the file into memory using `mmap` and then accessing that memory through a `koffi.view()`. Ensure the necessary C library functions are available and constants are correctly defined for your operating system. ```javascript import koffi from 'koffi'; // CJS: const koffi = require('koffi'); const libc = koffi.load('libc.so.6'); const mode_t = koffi.alias('mode_t', 'uint32_t'); const off_t = koffi.alias('off_t', 'int64_t'); // These values are used on Linux and may differ on other systems const O_RDONLY = 00000000; const O_WRONLY = 00000001; const O_RDWR = 00000002; const O_CREAT = 00000100; const O_EXCL = 00000200; const O_CLOEXEC = 02000000; // These values are used on Linux and may differ on other systems const PROT_READ = 0x01; const PROT_WRITE = 0x02; const PROT_EXEC = 0x04; const MAP_SHARED = 0x01; const MAP_PRIVATE = 0x02; const open = libc.func('int open(const char *path, int flags, uint32_t mode)'); const close = libc.func('int close(int fd)'); const ftruncate = libc.func('int ftruncate(int fd, off_t length)'); const mmap = libc.func('void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset)'); const munmap = libc.func('int munmap(void *addr, size_t length)'); const strerror = libc.func('const char *strerror(int errnum)'); write('hello.txt', 'Hello World!'); function write(filename, str) { let fd = -1; let ptr = null; // Work with encoded string str = Buffer.from(str); try { fd = open(filename, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC, 0644); if (fd < 0) throw new Error(`Failed to create '${filename}': ` + strerror(koffi.errno())); if (ftruncate(fd, str.length) < 0) throw new Error(`Failed to resize '${filename}': ` + strerror(koffi.errno())); ptr = mmap(null, str.length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (ptr == null) throw new Error(`Failed to map '${filename}' to memory: ` + strerror(koffi.errno())); let ab = koffi.view(ptr, str.length); let view = new Uint8Array(ab); str.copy(view); } finally { if (ptr != null) munmap(ptr, str.length); close(fd); } } ``` -------------------------------- ### Manage Test Machines with Brew Source: https://koffi.dev/contribute Control the lifecycle of test machines using the brew script. This includes starting all available machines, stopping all machines, or managing specific subsets. ```bash node tools/brew.js start # Start all available machines ``` ```bash node tools/brew.js stop # Stop everything ``` ```bash # Full test cycle node tools/brew.js test debian_x64 debian_i386 ``` ```bash # Separate start, test, shutdown node tools/brew.js start debian_x64 debian_i386 node tools/brew.js test debian_x64 debian_i386 node tools/brew.js stop ``` -------------------------------- ### Copy Struct Data Using memcpy with Transient Pointers Source: https://koffi.dev/output This example demonstrates using transient pointers with `Buffer.allocUnsafe` and `memcpy` to copy a `Vec3` struct. It shows how to decode the copied data back into a JavaScript object after the native call. ```javascript import koffi from 'koffi'; // CJS: const koffi = require('koffi'); const lib = koffi.load('libc.so.6'); const Vec3 = koffi.struct('Vec3', { x: 'float32', y: 'float32', z: 'float32' }) const memcpy = lib.func('void *memcpy(_Out_ void *dest, const void *src, size_t size)'); let vec1 = { x: 1, y: 2, z: 3 }; let vec2 = null; // Copy the vector in a convoluted way through memcpy { let src = koffi.as(vec1, 'Vec3 *'); let dest = Buffer.allocUnsafe(koffi.sizeof(Vec3)); memcpy(dest, src, koffi.sizeof(Vec3)); vec2 = koffi.decode(dest, Vec3); } // CHange vector1, leaving copy alone [vec1.x, vec1.y, vec1.z] = [vec1.z, vec1.y, vec1.x]; console.log(vec1); // { x: 3, y: 2, z: 1 } console.log(vec2); // { x: 1, y: 2, z: 3 } ``` -------------------------------- ### Declare and Use Opaque Type with SQLite Source: https://koffi.dev/output This example shows how to declare an opaque type for `sqlite3` and use it with C functions like `sqlite3_open_v2` and `sqlite3_close_v2`. It demonstrates opening an in-memory database and closing it. ```javascript import koffi from 'koffi'; // CJS: const koffi = require('koffi'); const lib = koffi.load('sqlite3.so'); const sqlite3 = koffi.opaque('sqlite3'); // Use koffi.out() on a double pointer to copy out (from C to JS) after the call const sqlite3_open_v2 = lib.func('sqlite3_open_v2', 'int', ['str', koffi.out(koffi.pointer(sqlite3, 2)), 'int', 'str']); const sqlite3_close_v2 = lib.func('sqlite3_close_v2', 'int', [koffi.pointer(sqlite3)]); const SQLITE_OPEN_READWRITE = 0x2; const SQLITE_OPEN_CREATE = 0x4; let out = [null]; if (sqlite3_open_v2(':memory:', out, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, null) != 0) throw new Error('Failed to open database'); let db = out[0]; sqlite3_close_v2(db); ``` -------------------------------- ### Pointers to Primitive Types: AddInt Example Source: https://koffi.dev/pointers Shows how to handle C functions that expect pointers to primitive types (like `int *`) for output or input/output parameters. This is achieved in JavaScript by passing single-element arrays. ```APIDOC ## Pointers to Primitive Types: AddInt Example ### Description This example demonstrates how to call a C function (`AddInt`) that modifies a primitive type through a pointer argument (`int *dest`). In JavaScript, this is handled by passing a single-element array, which Koffi then treats as a mutable reference. ### Method ```javascript // C function signature: // void AddInt(int *dest, int add) // Koffi function declaration: // const AddInt = lib.func('void AddInt(_Inout_ int *dest, int add)'); // Example usage: let sum = [36]; // Initialize a single-element array // AddInt(sum, 6); // console.log(sum[0]); // Prints 42 ``` ``` -------------------------------- ### Koffi 1.x Opaque Output Parameter Source: https://koffi.dev/migration Koffi 1.x handled opaque output parameters by passing an object that would be populated. This example shows `sqlite3_open_v2` using the older method. ```javascript // Koffi 1.x const sqlite3 = koffi.handle('sqlite3'); const sqlite3_open_v2 = lib.func('int sqlite3_open_v2(const char *, _Out_ sqlite3 *db, int, const char *)'); const sqlite3_close_v2 = lib.func('int sqlite3_close_v2(sqlite3 db)'); const SQLITE_OPEN_READWRITE = 0x2; const SQLITE_OPEN_CREATE = 0x4; let db = {}; if (sqlite3_open_v2(':memory:', db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, null) != 0) throw new Error('Failed to open database'); sqlite3_close_v2(db); ``` -------------------------------- ### Append Strings to Stable Pointer Buffer Source: https://koffi.dev/output This example uses `koffi.alloc` to create a stable memory buffer and C functions `reset_buffer` and `append_str` to manage string appends. It demonstrates decoding the buffer content after multiple appends. ```c #include #include static char *buf_ptr; static size_t buf_len; static size_t buf_size; void reset_buffer(char *buf, size_t size) { assert(size > 1); buf_ptr = buf; buf_len = 0; buf_size = size - 1; // Keep space for trailing NUL buf_ptr[0] = 0; } void append_str(const char *str) { for (size_t i = 0; str[i] && buf_len < buf_size; i++, buf_len++) { buf_ptr[buf_len] = str[i]; } buf_ptr[buf_len] = 0; } ``` ```javascript const reset_buffer = lib.func('void reset_buffer(char *buf, size_t size)'); const append_str = lib.func('void append_str(const char *str)'); let output = koffi.alloc('char', 64); reset_buffer(output, 64); append_str('Hello'); console.log(koffi.decode(output, 'char', -1)); // Prints Hello append_str(' World!'); console.log(koffi.decode(output, 'char', -1)); // Prints Hello World! ``` -------------------------------- ### Call Variadic Functions Source: https://koffi.dev/functions Call variadic functions by providing pairs of expected C type and value for each variadic argument. This example shows calling `printf` with integer, double, and string arguments. ```javascript const printf = lib.func('printf', 'int', ['str', '...']); // The variadic arguments are: 6 (int), 8.5 (double), 'THE END' (const char *) printf('Integer %d, double %g, str %s', 'int', 6, 'double', 8.5, 'str', 'THE END'); ``` -------------------------------- ### Struct Pointers: GetCursorPos Example Source: https://koffi.dev/pointers Demonstrates using a struct pointer with the `GetCursorPos` function from user32.dll to retrieve the current cursor position. Koffi's `koffi.struct` is used to define the `POINT` structure. ```APIDOC ## Struct Pointers: GetCursorPos Example ### Description This example shows how to use a struct pointer to get the current cursor position using the Win32 API function `GetCursorPos`. It defines a `POINT` struct and then calls the function, logging the result. ### Method ```javascript const lib = koffi.load('user32.dll'); const POINT = koffi.struct('POINT', { x: 'long', y: 'long' }); const GetCursorPos = lib.func('int __stdcall GetCursorPos(_Out_ POINT *pos)'); let pos = {}; if (!GetCursorPos(pos)) { throw new Error('Failed to get cursor position'); } console.log(pos); ``` ``` -------------------------------- ### Koffi 1.x Callback Definition Source: https://koffi.dev/migration In Koffi 1.x, callback functions could be used directly as parameter and return types. This example shows the older syntax for defining and using a callback. ```javascript // Koffi 1.x const TransferCallback = koffi.proto('int TransferCallback(const char *str, int age)'); const TransferToJS = lib.func('TransferToJS', 'int', ['str', 'int', TransferCallback]); // Equivalent to: const TransferToJS = lib.func('int TransferToJS(str s, int x, TransferCallback cb)'); let ret = TransferToJS('Niels', 27, (str, age) => { console.log(str); console.log('Your age is:', age); return 42; }); console.log(ret); ``` -------------------------------- ### Reading PNG Header with void* Source: https://koffi.dev/pointers This example demonstrates reading a PNG file header directly into a JavaScript object using Koffi's `koffi.as()` function with a `void *` parameter for `fread`. It defines a packed structure for the PNG header. ```javascript import koffi from 'koffi'; // CJS: const koffi = require('koffi'); const lib = koffi.load('libc.so.6'); const FILE = koffi.opaque('FILE'); const PngHeader = koffi.pack('PngHeader', { signature: koffi.array('uint8_t', 8), ihdr: koffi.pack({ length: 'uint32_be_t', chunk: koffi.array('char', 4), width: 'uint32_be_t', height: 'uint32_be_t', depth: 'uint8_t', color: 'uint8_t', compression: 'uint8_t', filter: 'uint8_t', interlace: 'uint8_t', crc: 'uint32_be_t' }) }); const fopen = lib.func('FILE *fopen(const char *path, const char *mode)'); const fclose = lib.func('int fclose(FILE *fp)'); const fread = lib.func('size_t fread(_Out_ void *ptr, size_t size, size_t nmemb, FILE *fp)'); let filename = process.argv[2]; if (filename == null) throw new Error('Usage: node png.js '); let hdr = {}; { let fp = fopen(filename, 'rb'); if (!fp) throw new Error(`Failed to open '${filename}'`); try { let len = fread(koffi.as(hdr, 'PngHeader *'), 1, koffi.sizeof(PngHeader), fp); if (len < koffi.sizeof(PngHeader)) throw new Error('Failed to read PNG header'); } finally { fclose(fp); } } console.log('PNG header:', hdr); ``` -------------------------------- ### Koffi 2.1 Opaque Handle Usage Source: https://koffi.dev/migration Koffi 2.1 uses `koffi.opaque()` for opaque types and requires them to be passed as pointers (e.g., `FILE *`). This example demonstrates modern file handling. ```javascript // Koffi 2.1 // If you use Koffi 2.0: const FILE = koffi.handle('FILE'); const FILE = koffi.opaque('FILE'); const fopen = lib.func('fopen', 'FILE *', ['str', 'str']); const fopen = lib.func('fclose', 'int', ['FILE *']); let fp = fopen('EMPTY', 'wb'); if (!fp) throw new Error('Failed to open file'); fclose(fp); ``` -------------------------------- ### Koffi 1.x Opaque Handle Usage Source: https://koffi.dev/migration In Koffi 1.x, opaque handles like `FILE` were defined using `koffi.handle()` and used directly. This example shows file operations using the older API. ```javascript // Koffi 1.x const FILE = koffi.handle('FILE'); const fopen = lib.func('fopen', 'FILE', ['str', 'str']); const fopen = lib.func('fclose', 'int', ['FILE']); let fp = fopen('EMPTY', 'wb'); if (!fp) throw new Error('Failed to open file'); fclose(fp); ``` -------------------------------- ### Koffi 2.1 Opaque Output Parameter Source: https://koffi.dev/migration Koffi 2.1 requires opaque output parameters to be passed as a single-element array, which will then contain the opaque pointer. This example demonstrates `sqlite3_open_v2` with the updated API. ```javascript // Koffi 2.1 // If you use Koffi 2.0: const sqlite3 = koffi.handle('sqlite3'); const sqlite3 = koffi.opaque('sqlite3'); const sqlite3_open_v2 = lib.func('int sqlite3_open_v2(const char *, _Out_ sqlite3 **db, int, const char *)'); const sqlite3_close_v2 = lib.func('int sqlite3_close_v2(sqlite3 *db)'); const SQLITE_OPEN_READWRITE = 0x2; const SQLITE_OPEN_CREATE = 0x4; let db = null; let ptr = [null]; if (sqlite3_open_v2(':memory:', ptr, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, null) != 0) throw new Error('Failed to open database'); db = ptr[0]; sqlite3_close_v2(db); ``` -------------------------------- ### Registering Callbacks with Explicit 'this' Binding Source: https://koffi.dev/callbacks This example shows how to register a callback function with an explicit 'this' context using `koffi.register`. The first argument to `koffi.register` is the 'this' object, followed by the function and its type. This is useful when the C function expects a method bound to a specific object. ```javascript class ValueStore { constructor(value) { this.value = value; } get() { return this.value; } } let store = new ValueStore(42); let cb1 = koffi.register(store.get, 'IntCallback *'); // If a C function calls cb1 it will fail because this will be undefined let cb2 = koffi.register(store, store.get, 'IntCallback *'); // However in this case, this will match the store object ``` -------------------------------- ### Define and Use C String Concatenation Function Source: https://koffi.dev/output This example defines a C function `ConcatToBuffer` that concatenates two strings into a pre-allocated buffer. It then demonstrates calling this function from JavaScript using Koffi, passing a JS array containing a string as the output buffer. ```c void ConcatToBuffer(const char *str1, const char *str2, char *out) { size_t len = 0; for (size_t i = 0; str1[i]; i++) { out[len++] = str1[i]; } for (size_t i = 0; str2[i]; i++) { out[len++] = str2[i]; } out[len] = 0; } ``` ```javascript const ConcatToBuffer = lib.func('void ConcatToBuffer(const char *str1, const char *str2, _Out_ char *out)'); let str1 = 'Hello '; let str2 = 'Friends!'; // We need to reserve space for the output buffer! Including the NUL terminator // because ConcatToBuffer() expects so, but Koffi can convert back to a JS string // without it (if we reserve the right size). let out = ['\0'.repeat(str1.length + str2.length + 1)]; ConcatToBuffer(str1, str2, out); console.log(out[0]); ``` -------------------------------- ### Get Current Koffi Configuration Settings Source: https://koffi.dev/misc Retrieve the current configuration settings for Koffi's memory management using `koffi.config()`. This returns an object containing parameters like default memory block sizes for synchronous and asynchronous operations. ```javascript let config = koffi.config(); console.log(config); ``` -------------------------------- ### Build Koffi on Windows Source: https://koffi.dev/contribute Navigate to the Koffi source directory and use the provided script to build the project. Use the --debug flag for debug builds. ```bash cd src/koffi node ../cnoke/cnoke.js ``` ```bash cd src/koffi node ../cnoke/cnoke.js --debug ``` -------------------------------- ### Run Benchmarks Source: https://koffi.dev/benchmarks Execute the benchmark tests after building the Koffi binaries. Ensure you are in the benchmark directory. ```bash node benchmark.js ``` -------------------------------- ### Run All Tests with Brew Source: https://koffi.dev/contribute Execute the full test suite using the brew script. This command can take a significant amount of time, especially for emulated machines. ```bash cd src/koffi node tools/brew.js test # Several options are available, use --help ``` -------------------------------- ### Build Koffi Binaries with Clang Source: https://koffi.dev/benchmarks Build Koffi binaries using Clang for release. This is a prerequisite for running the benchmarks. ```bash cd src/koffi node ../cnoke/cnoke.js --clang --release ``` ```bash cd benchmark node ../../cnoke/cnoke.js --clang --release ``` -------------------------------- ### Build and Run C Tests Source: https://koffi.dev/contribute Compile the C test code and then execute the tests. This is done after building Koffi. ```bash cd src/koffi/test node ../../cnoke/cnoke.js # Build C test code node test.js ``` -------------------------------- ### Get Primitive Value from Output Argument (Win32) Source: https://koffi.dev/output Illustrates retrieving a primitive value (PID) from an output argument using `GetWindowThreadProcessId`. Ensure the process has not ended between calls. ```javascript import koffi from 'koffi'; // CJS: const koffi = require('koffi'); const user32 = koffi.load('user32.dll'); const DWORD = koffi.alias('DWORD', 'uint32_t'); const HANDLE = koffi.pointer('HANDLE', koffi.opaque()); const HWND = koffi.alias('HWND', HANDLE); const FindWindowEx = user32.func('HWND __stdcall FindWindowExW(HWND hWndParent, HWND hWndChildAfter, const char16_t *lpszClass, const char16_t *lpszWindow)'); const GetWindowThreadProcessId = user32.func('DWORD __stdcall GetWindowThreadProcessId(HWND hWnd, _Out_ DWORD *lpdwProcessId)'); const GetWindowText = user32.func('int __stdcall GetWindowTextA(HWND hWnd, _Out_ uint8_t *lpString, int nMaxCount)'); for (let hwnd = null;;) { hwnd = FindWindowEx(0, hwnd, 'Chrome_WidgetWin_1', null); if (!hwnd) break; // Get PID let pid; { let ptr = [null]; let tid = GetWindowThreadProcessId(hwnd, ptr); if (!tid) { // Maybe the process ended in-between? continue; } pid = ptr[0]; } // Get window title let title; { let buf = Buffer.allocUnsafe(1024); let length = GetWindowText(hwnd, buf, buf.length); if (!length) { // Maybe the process ended in-between? continue; } title = koffi.decode(buf, 'char', length); } console.log({ PID: pid, Title: title }); } ``` -------------------------------- ### Directory Structure for Native Modules Source: https://koffi.dev/packaging Illustrates the expected directory structure for Koffi's native modules when manually copying them next to your bundled script. ```text koffi/ win32_x64/ koffi.node linux_x64/ koffi.node ... MyBundle.js ``` -------------------------------- ### Configure esbuild to Copy Native Files Source: https://koffi.dev/packaging Command to bundle a Node.js project with esbuild, instructing it to copy `.node` files using the `copy` loader. This ensures native modules are included in the output. ```bash esbuild index.js --platform=node --bundle --loader:.node=copy --outdir=dist/ ``` -------------------------------- ### Prepare and Publish Release Source: https://koffi.dev/contribute Commands to build and publish a new release of Koffi. This involves updating version numbers, committing changes, running tests, building, and then preparing and publishing packages. ```bash cd src/koffi node tools/brew.js test # If not done before node tools/brew.js build cd ../../bin/koffi/packages ./prepare.sh ./publish.sh ``` -------------------------------- ### C Functions to Register Callbacks Source: https://koffi.dev/callbacks These C functions, `RegisterFunctions` and `SayIt`, demonstrate how to store and invoke registered callback functions. `RegisterFunctions` assigns the provided callbacks to global pointers, and `SayIt` uses these pointers to execute the callbacks. ```c void RegisterFunctions(const char *(*cb1)(const char *name), void (*cb2)(const char *str)) { g_cb1 = cb1; g_cb2 = cb2; } void SayIt(const char *name) { const char *str = g_cb1(name); g_cb2(str); } ``` -------------------------------- ### Sorting an Array of Strings using qsort with Callbacks Source: https://koffi.dev/callbacks This JavaScript code demonstrates how to use the C standard library function `qsort` to sort an array of strings in-place. It utilizes `koffi.decode` to convert raw pointer arguments received by the callback into JavaScript strings for comparison. ```javascript import koffi from 'koffi'; // CJS: const koffi = require('koffi'); const lib = koffi.load('libc.so.6'); const SortCallback = koffi.proto('int SortCallback(const void *first, const void *second)'); const qsort = lib.func('void qsort(_Inout_ void *array, size_t count, size_t size, SortCallback *cb)'); let array = ['foo', 'bar', '123', 'foobar']; qsort(koffi.as(array, 'char **'), array.length, koffi.sizeof('void *'), (ptr1, ptr2) => { let str1 = koffi.decode(ptr1, 'char *'); let str2 = koffi.decode(ptr2, 'char *'); return str1.localeCompare(str2); }); console.log(array); // Prints ['123', 'bar', 'foo', 'foobar'] ``` -------------------------------- ### Directory Structure for Electron Resources Source: https://koffi.dev/packaging Shows the directory structure for Koffi's native modules when placed within Electron's `process.resourcesPath`. ```text locales/ resources/ koffi/ win32_ia32/ koffi.node win32_x64/ koffi.node ... MyApp.exe ``` -------------------------------- ### Use Flexible Array API from C Source: https://koffi.dev/input This example demonstrates calling a C function that manipulates a struct with a flexible array member. The `AppendValues` function dynamically adds integers to the `numbers` array, updating the `count` member. ```c // Build with: clang -fPIC -o flexible.so -shared flexible.c -Wall -O2 #include struct FlexibleArray { size_t count; int numbers[]; }; void AppendValues(struct FlexibleArray *arr, size_t count, int start, int step) { for (size_t i = 0; i < count; i++) { arr->numbers[arr->count + i] = start + i * step; } arr->count += count; } ``` -------------------------------- ### Get Cursor Position using Struct Pointer Source: https://koffi.dev/pointers Retrieves the current cursor position using the Win32 API's GetCursorPos function, which takes a pointer to a POINT struct as an output parameter. Ensure user32.dll is accessible. ```javascript import koffi from 'koffi'; // CJS: const koffi = require('koffi'); const lib = koffi.load('user32.dll'); // Type declarations const POINT = koffi.struct('POINT', { x: 'long', y: 'long' }); // Functions declarations const GetCursorPos = lib.func('int __stdcall GetCursorPos(_Out_ POINT *pos)'); // Get and show cursor position let pos = {}; if (!GetCursorPos(pos)) throw new Error('Failed to get cursor position'); console.log(pos); ``` -------------------------------- ### Get Size of a Primitive Type in Koffi Source: https://koffi.dev/misc Use `koffi.sizeof` to retrieve the memory size of a given type. You can pass either a type string or a Koffi type object. This is helpful for memory calculations and understanding data representation. ```javascript // These two lines do the same: console.log(koffi.sizeof('long')); console.log(koffi.sizeof(koffi.types.long)); ``` -------------------------------- ### Define Functions using C-like Prototypes Source: https://koffi.dev/functions Declare C functions using C-like prototype strings for a more familiar syntax. Parameter names are optional and not used by Koffi. ```javascript const printf = lib.func('int printf(const char *fmt, ...)'); const atoi = lib.func('int atoi(str)'); // The parameter name is not used by Koffi, and optional ``` -------------------------------- ### Build Koffi on Other Platforms Source: https://koffi.dev/contribute After ensuring dependencies are met, run the build script from the Koffi source directory. Debug builds can be enabled with the --debug flag. ```bash cd src/koffi node ../cnoke/cnoke.js ``` ```bash cd src/koffi node ../cnoke/cnoke.js --debug ``` -------------------------------- ### Get Win32 Struct Output with Size Member (_Inout_) Source: https://koffi.dev/output Shows how to use `_Inout_` for Win32 functions like `GetLastInputInfo` that require a size member (`cbSize`) to be set before calling. The struct is marshaled in to set `cbSize` and then marshaled out with the results. ```javascript import koffi from 'koffi'; // CJS: const koffi = require('koffi'); const user32 = koffi.load('user32.dll'); const LASTINPUTINFO = koffi.struct('LASTINPUTINFO', { cbSize: 'uint', dwTime: 'uint32' }); const GetLastInputInfo = user32.func('bool __stdcall GetLastInputInfo(_Inout_ LASTINPUTINFO *plii)'); let info = { cbSize: koffi.sizeof(LASTINPUTINFO) }; let success = GetLastInputInfo(info); console.log(success, info); ``` -------------------------------- ### SSH into a Test Machine Source: https://koffi.dev/contribute Connect to a running test machine via SSH for debugging or manual operations. Replace 'debian_i386' with the desired machine name. ```bash node tools/brew.js ssh debian_i386 ``` -------------------------------- ### Defining Functions - C-like Prototypes Source: https://koffi.dev/functions Declare functions using C-like prototype strings for a more familiar syntax. ```APIDOC ## Defining Functions - C-like Prototypes Use `lib.func('returnType functionName(paramType paramName, ...)')`. ### Example ```javascript const printf = lib.func('int printf(const char *fmt, ...)'); const atoi = lib.func('int atoi(str)'); // Parameter names are optional ``` Use `()` or `(void)` for functions with no arguments. ``` -------------------------------- ### Registering and Unregistering Callbacks in JavaScript Source: https://koffi.dev/callbacks This JavaScript code demonstrates how to load a C library, define function prototypes, register JavaScript functions as callbacks using `koffi.register`, and then unregister them. It shows how to pass these callbacks to C functions and invoke them. ```javascript import koffi from 'koffi'; // CJS: const koffi = require('koffi'); const lib = koffi.load('./callbacks.so'); // Fake path const GetCallback = koffi.proto('const char *GetCallback(const char *name)'); const PrintCallback = koffi.proto('void PrintCallback(const char *str)'); const RegisterFunctions = lib.func('void RegisterFunctions(GetCallback *cb1, PrintCallback *cb2)'); const SayIt = lib.func('void SayIt(const char *name)'); let cb1 = koffi.register(name => 'Hello ' + name + '!', koffi.pointer(GetCallback)); let cb2 = koffi.register(console.log, 'PrintCallback *'); RegisterFunctions(cb1, cb2); SayIt('Kyoto'); // Prints Hello Kyoto! koffi.unregister(cb1); koffi.unregister(cb2); ``` -------------------------------- ### Define Functions using Classic Syntax Source: https://koffi.dev/functions Declare C functions using the classic syntax, specifying the function name, return type, and an array of parameter types. Use '...' for variadic functions. ```javascript const printf = lib.func('printf', 'int', ['str', '...']); const atoi = lib.func('atoi', 'int', ['str']); ``` -------------------------------- ### Call Function Pointer Directly Source: https://koffi.dev/functions Demonstrates calling a function pointer directly using `koffi.call()`. This method requires the function pointer, its type signature, and the arguments for the call. ```APIDOC ## Call Function Pointer Directly ### Description Invoke a function pointer directly using `koffi.call(ptr, type, ...)`. ### Method `koffi.call(functionPointer, functionType, arg1, arg2, ...)`. ### Example ```javascript // Declare function type const BinaryIntFunc = koffi.proto('int BinaryIntFunc(int a, int b)'); const GetBinaryIntFunction = lib.func('BinaryIntFunc *GetBinaryIntFunction(const char *name)'); const add_ptr = GetBinaryIntFunction('add'); const substract_ptr = GetBinaryIntFunction('substract'); let sum = koffi.call(add_ptr, BinaryIntFunc, 4, 5); let delta = koffi.call(substract_ptr, BinaryIntFunc, 100, 58); console.log(sum, delta); // Prints 9 and 42 ``` ``` -------------------------------- ### Synchronous Variadic Function Call Source: https://koffi.dev/functions Shows how to call variadic C functions. You must specify the type and value for each additional argument after the fixed arguments. ```APIDOC ## Synchronous Variadic Function Call ### Description Call a variadic native function by explicitly providing types and values for variadic arguments. ### Method `lib.func(name, returnType, argTypes)` followed by invocation with explicit type-value pairs for variadic arguments. ### Example ```javascript const printf = lib.func('printf', 'int', ['str', '...']); // The variadic arguments are: 6 (int), 8.5 (double), 'THE END' (const char *) printf('Integer %d, double %g, str %s', 'int', 6, 'double', 8.5, 'str', 'THE END'); ``` ``` -------------------------------- ### Koffi Union Handling and Usage Source: https://koffi.dev/unions Demonstrates defining a union in Koffi, binding C functions, and using `koffi.Union` to pass and retrieve union values. ```javascript const IntOrDouble = koffi.union('IntOrDouble', { i: 'int64_t', d: 'double', raw: koffi.array('uint8_t', 8) }); const SetUnionInt = lib.func('void SetUnionInt(int64_t i, _Out_ IntOrDouble *out)'); const SetUnionDouble = lib.func('void SetUnionDouble(double d, _Out_ IntOrDouble *out)'); let u1 = new koffi.Union('IntOrDouble'); let u2 = new koffi.Union('IntOrDouble'); SetUnionInt(123, u1); SetUnionDouble(123, u2); console.log(u1.i, '---', u1.raw); console.log(u2.d, '---', u2.raw); ``` -------------------------------- ### Synchronous Function Call Source: https://koffi.dev/functions Demonstrates how to declare and call a native function synchronously. The function signature is provided to `lib.func()` and then called like a regular JavaScript function. ```APIDOC ## Synchronous Function Call ### Description Call a native function synchronously after declaring its signature. ### Method `lib.func(signature)` followed by direct invocation. ### Example ```javascript const atoi = lib.func('int atoi(const char *str)'); let value = atoi('1257'); console.log(value); ``` ```