@@ -204,40 +204,41 @@ console.log(`${st.wYear}-${st.wMonth}-${st.wDay}`);
204204
205205## API Compatibility Reference
206206
207- | Feature | Python ctypes | node-ctypes |
208- | -------------------- | --------------------------------- | ----------------------------------------------- |
209- | Load library | ` CDLL("lib.so") ` | ` new CDLL("lib.so") ` |
210- | Function setup | ` f.argtypes = [c_int] ` | ` f.argtypes = [c_int] ` |
211- | Structs | ` class P(Structure): ` | ` class P extends Structure ` |
212- | Unions | ` class U(Union): ` | ` class U extends Union ` |
213- | Arrays | ` c_int * 5 ` | ` array(c_int, 5) ` |
214- | Bit fields | ` ("f", c_uint, 3) ` | ` ["f", c_uint32, 3] ` |
215- | Callbacks | ` CFUNCTYPE(c_int, c_int) ` | ` CFUNCTYPE(c_int, c_int) ` |
216- | Pointers | ` POINTER(c_int) ` / ` pointer(obj) ` | ` POINTER(c_int) ` / ` pointer(obj) ` |
217- | Pointer arithmetic | ` p[i] ` , C-style ` ptr + n ` | ` p[i] ` , ` p.add(n) ` , ` p.slice(a, b) ` |
218- | Sizeof | ` sizeof(c_int) ` | ` sizeof(c_int) ` |
219- | Alignment | ` alignment(c_int) ` | ` alignment(c_int) ` |
220- | Strings | ` c_char_p(b"hello") ` | ` create_string_buffer("hello") ` |
221- | Variadic | ` sprintf(buf, b"%d", 42) ` | ` sprintf(buf, "%d", 42) ` |
222- | Errno | ` get_errno() ` | ` get_errno() ` |
223- | byref | ` byref(obj) ` | ` byref(obj) ` |
224- | cast | ` cast(ptr, type) ` | ` cast(ptr, type) ` (supports ` POINTER() ` target) |
225- | Find library | ` ctypes.util.find_library("c") ` | ` find_library("c") ` |
226- | Lazy load | ` ctypes.cdll.msvcrt.printf(...) ` | ` cdll.msvcrt.printf(...) ` |
227- | ` from_buffer ` | ` S.from_buffer(buf) ` | ` S.from_buffer(buf) ` |
228- | ` from_buffer_copy ` | ` S.from_buffer_copy(buf) ` | ` S.from_buffer_copy(buf) ` |
229- | ` from_address ` | ` S.from_address(addr) ` | ` S.from_address(addr) ` |
230- | ` in_dll ` | ` c_int.in_dll(lib, "errno") ` | ` c_int.in_dll(lib, "errno") ` |
231- | ` _as_parameter_ ` | Unwrap on call | Unwrap on call |
232- | ` from_param ` | Custom conversion | Custom conversion |
233- | ` use_last_error ` | ` CDLL(..., use_last_error=True) ` | ` new CDLL(..., { use_last_error: true }) ` |
234- | ` use_errno ` | ` CDLL(..., use_errno=True) ` | ` new CDLL(..., { use_errno: true }) ` |
235- | ` OleDLL ` / ` HRESULT ` | ` OleDLL("ole32") ` auto-raises | ` new OleDLL("ole32.dll") ` auto-throws |
236- | ` paramflags ` | ` proto((name, lib), paramflags) ` | ` proto.bind(lib, name, paramflags) ` |
237- | Big-endian struct | ` class X(BigEndianStructure) ` | ` class X extends BigEndianStructure ` |
238- | Little-endian struct | ` class X(LittleEndianStructure) ` | ` class X extends LittleEndianStructure ` |
239- | Big-endian union | ` class X(BigEndianUnion) ` | ` class X extends BigEndianUnion ` |
240- | Little-endian union | ` class X(LittleEndianUnion) ` | ` class X extends LittleEndianUnion ` |
207+ | Feature | Python ctypes | node-ctypes |
208+ | --------------------- | --------------------------------------- | ----------------------------------------------- |
209+ | Load library | ` CDLL("lib.so") ` | ` new CDLL("lib.so") ` |
210+ | Function setup | ` f.argtypes = [c_int] ` | ` f.argtypes = [c_int] ` |
211+ | Structs | ` class P(Structure): ` | ` class P extends Structure ` |
212+ | Unions | ` class U(Union): ` | ` class U extends Union ` |
213+ | Arrays | ` c_int * 5 ` | ` array(c_int, 5) ` |
214+ | Bit fields | ` ("f", c_uint, 3) ` | ` ["f", c_uint32, 3] ` |
215+ | Callbacks | ` CFUNCTYPE(c_int, c_int) ` | ` CFUNCTYPE(c_int, c_int) ` |
216+ | Pointers | ` POINTER(c_int) ` / ` pointer(obj) ` | ` POINTER(c_int) ` / ` pointer(obj) ` |
217+ | Pointer arithmetic | ` p[i] ` , C-style ` ptr + n ` | ` p[i] ` , ` p.add(n) ` , ` p.slice(a, b) ` |
218+ | Sizeof | ` sizeof(c_int) ` | ` sizeof(c_int) ` |
219+ | Alignment | ` alignment(c_int) ` | ` alignment(c_int) ` |
220+ | Strings | ` c_char_p(b"hello") ` | ` create_string_buffer("hello") ` |
221+ | Variadic | ` sprintf(buf, b"%d", 42) ` | ` sprintf(buf, "%d", 42) ` |
222+ | Errno slot | ` get_errno() ` / ` set_errno() ` | ` get_errno() ` / ` set_errno() ` |
223+ | Last-error slot (Win) | ` get_last_error() ` / ` set_last_error() ` | ` GetLastError() ` / ` SetLastError() ` |
224+ | byref | ` byref(obj) ` | ` byref(obj) ` |
225+ | cast | ` cast(ptr, type) ` | ` cast(ptr, type) ` (supports ` POINTER() ` target) |
226+ | Find library | ` ctypes.util.find_library("c") ` | ` find_library("c") ` |
227+ | Lazy load | ` ctypes.cdll.msvcrt.printf(...) ` | ` cdll.msvcrt.printf(...) ` |
228+ | ` from_buffer ` | ` S.from_buffer(buf) ` | ` S.from_buffer(buf) ` |
229+ | ` from_buffer_copy ` | ` S.from_buffer_copy(buf) ` | ` S.from_buffer_copy(buf) ` |
230+ | ` from_address ` | ` S.from_address(addr) ` | ` S.from_address(addr) ` |
231+ | ` in_dll ` | ` c_int.in_dll(lib, "errno") ` | ` c_int.in_dll(lib, "errno") ` |
232+ | ` _as_parameter_ ` | Unwrap on call | Unwrap on call |
233+ | ` from_param ` | Custom conversion | Custom conversion |
234+ | ` use_last_error ` | ` CDLL(..., use_last_error=True) ` | ` new CDLL(..., { use_last_error: true }) ` |
235+ | ` use_errno ` | ` CDLL(..., use_errno=True) ` | ` new CDLL(..., { use_errno: true }) ` |
236+ | ` OleDLL ` / ` HRESULT ` | ` OleDLL("ole32") ` auto-raises | ` new OleDLL("ole32.dll") ` auto-throws |
237+ | ` paramflags ` | ` proto((name, lib), paramflags) ` | ` proto.bind(lib, name, paramflags) ` |
238+ | Big-endian struct | ` class X(BigEndianStructure) ` | ` class X extends BigEndianStructure ` |
239+ | Little-endian struct | ` class X(LittleEndianStructure) ` | ` class X extends LittleEndianStructure ` |
240+ | Big-endian union | ` class X(BigEndianUnion) ` | ` class X extends BigEndianUnion ` |
241+ | Little-endian union | ` class X(LittleEndianUnion) ` | ` class X extends LittleEndianUnion ` |
241242
242243## Supported Types
243244
@@ -290,17 +291,29 @@ const CoInit = ole32.func("CoInitializeEx", HRESULT, [c_void_p, c_uint32]);
290291CoInit (null , 0 ); // throws on failure, no manual check needed
291292```
292293
293- ### Snapshotted errno / GetLastError
294+ ### Snapshotted errno / GetLastError (Python ctypes parity)
295+
296+ ` GetLastError() ` / ` get_errno() ` read a ** private thread-local slot** — exactly
297+ like ` ctypes.get_last_error() ` / ` ctypes.get_errno() ` in Python. The slot is
298+ updated ** only** by FFI calls through libraries opened with ` use_last_error `
299+ or ` use_errno ` . If you never set that flag, the slot stays at 0.
294300
295301``` javascript
302+ import { WinDLL , GetLastError , c_void_p , c_wchar_p } from " node-ctypes" ;
303+
296304const user32 = new WinDLL (" user32.dll" , { use_last_error: true });
297305const FindWindow = user32 .func (" FindWindowW" , c_void_p, [c_wchar_p, c_wchar_p]);
306+
298307FindWindow (" NoSuchClass" , null );
299- console .log (user32 .get_last_error ()); // ERROR_CANNOT_FIND_WND_CLASS
308+
309+ // Both read the same snapshot — the one taken atomically in native code
310+ // immediately after ffi_call, before any other JS can clobber it.
311+ console .log (GetLastError ()); // top-level API (Python: ctypes.get_last_error)
312+ console .log (user32 .get_last_error ()); // per-library alias
300313```
301314
302- The snapshot is taken inside the native bridge immediately after ` ffi_call ` ,
303- so other Node.js code can't clobber it before you read it back .
315+ To read the ** system ** ` GetLastError() ` directly (ignoring the private slot) ,
316+ call the Win32 API manually as any other FFI function — same as Python .
304317
305318### ` paramflags ` — out parameters become return values
306319
0 commit comments