C functions and native memory
To call Objective-C classes and methods, start with Objective-C from JavaScript. This guide covers known C functions and memory buffers. Incorrect addresses or signatures can crash the target process.
C calls in the local automation context. RemoteC.forApp(bundleId) selects a running app with its helper enabled; it does not launch it. const app = RemoteC.forApp("com.apple.Preferences") gives you the same methods as C. Keep buffers and function handles in their original client/session.
C signatures
const length = C.bind("strlen", {returns: "size_t", args: ["cstring"]});
console.log(length("Hello"));
length.release();Supported names: void (return only), bool, int8, uint8, int16, uint16, int32, uint32, int64, uint64, long, ulong, size_t, float, double, pointer, cstring, object, class, selector, and CGRect, CGPoint, CGSize, NSRange, UIEdgeInsets, CGAffineTransform, CGVector, UIOffset. long and size_t are 64-bit. Up to 32 fixed arguments are supported.
Signatures require returns and args. For bind() and call(), optional library loads an absolute dylib/framework executable path. bindAddress() rejects library; omit it. ownership:"retained" applies only to object results whose native ownership is +1; the default is borrowed. captureErrno:true returns {value, errno} captured around that call.
Variadic calls, callbacks, arbitrary custom structures and unions are unsupported. Objective-C non-null blocks and arbitrary pointer arguments are not supported by ObjC; use a known C signature where appropriate. Symbol resolution cannot infer the correct declaration.
Structures use plain JavaScript objects with these fields:
| Type | Fields |
|---|---|
| CGRect | x, y, width, height |
| CGPoint / CGSize | x, y / width, height |
| NSRange | location, length |
| UIEdgeInsets | top, left, bottom, right |
| CGAffineTransform | a, b, c, d, tx, ty |
| CGVector / UIOffset | dx, dy / horizontal, vertical |
Calls are synchronous and run on the target main thread. Avoid blocking native functions. A remote timeout does not undo an action already executing; reconnect after a process restart and reacquire handles.
Managed buffers
const buffer = C.alloc(4);
try {
buffer.writeBytes([65, 66, 67, 0]);
console.log(buffer.readBytes());
} finally {
buffer.release();
}Managed allocations are limited to 16 MiB each and 64 MiB per session. Reads/writes allow at most 65536 bytes per operation. Use release(), not free/realloc. Releasing an external pointer handle does not free external memory. Closing either a C or ObjC client invalidates their shared references.
bindAddress() requires a verified absolute runtime function address in the selected process. Addresses change with ASLR and app restarts. Executable memory and alignment checks do not establish that an address is a valid function entry or that your signature is correct.