node-ctypes 1.2.0 → 1.4.0
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.
- package/README.md +125 -10
- package/build/Release/ctypes-darwin-arm64.node +0 -0
- package/build/Release/ctypes-darwin-x64.node +0 -0
- package/build/Release/ctypes-linux-arm64.node +0 -0
- package/build/Release/ctypes-linux-x64.node +0 -0
- package/build/Release/ctypes-win32-arm64.node +0 -0
- package/build/Release/ctypes-win32-x64.node +0 -0
- package/lib/core/Library.js +251 -211
- package/lib/core/types.js +7 -0
- package/lib/index.d.ts +28 -2
- package/lib/index.js +56 -59
- package/lib/memory/pointer.js +243 -25
- package/lib/structures/Structure.js +261 -230
- package/lib/structures/Union.js +10 -2
- package/lib/structures/helpers/common.js +9 -1
- package/lib/structures/helpers/struct.js +6 -1
- package/lib/structures/helpers/union.js +9 -19
- package/lib/types/primitives.js +1 -1
- package/package.json +1 -1
package/lib/core/Library.js
CHANGED
|
@@ -51,255 +51,295 @@
|
|
|
51
51
|
* @private
|
|
52
52
|
*/
|
|
53
53
|
export function createLibraryClasses(Library, LRUCache, _toNativeType, _toNativeTypes, native) {
|
|
54
|
-
class FunctionWrapper {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
54
|
+
class FunctionWrapper {
|
|
55
|
+
constructor(cdll, name) {
|
|
56
|
+
const argtypes = [];
|
|
57
|
+
let restype = undefined;
|
|
58
|
+
let cachedFunc = null;
|
|
59
59
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
}
|
|
65
|
-
if (!cachedFunc) {
|
|
66
|
-
cachedFunc = cdll.func(name, restype, argtypes);
|
|
67
|
-
}
|
|
68
|
-
return cachedFunc(...args);
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
// Proxy the function to intercept property access
|
|
72
|
-
return new Proxy(func, {
|
|
73
|
-
get(target, prop) {
|
|
74
|
-
if (prop === "argtypes") return argtypes;
|
|
75
|
-
if (prop === "restype") return restype;
|
|
76
|
-
if (prop === "errcheck") return cachedFunc ? cachedFunc.errcheck : undefined;
|
|
77
|
-
return target[prop];
|
|
78
|
-
},
|
|
79
|
-
set(target, prop, value) {
|
|
80
|
-
if (prop === "argtypes") {
|
|
81
|
-
argtypes.splice(0, argtypes.length, ...value);
|
|
82
|
-
cachedFunc = null; // Invalidate cache
|
|
83
|
-
return true;
|
|
60
|
+
// Create a function and proxy it to make it callable
|
|
61
|
+
const func = (...args) => {
|
|
62
|
+
if (restype === undefined) {
|
|
63
|
+
throw new Error(`Function ${name}: restype not set`);
|
|
84
64
|
}
|
|
85
|
-
if (
|
|
86
|
-
|
|
87
|
-
cachedFunc = null; // Invalidate cache
|
|
88
|
-
return true;
|
|
65
|
+
if (!cachedFunc) {
|
|
66
|
+
cachedFunc = cdll.func(name, restype, argtypes);
|
|
89
67
|
}
|
|
90
|
-
|
|
91
|
-
|
|
68
|
+
return cachedFunc(...args);
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
// Proxy the function to intercept property access
|
|
72
|
+
return new Proxy(func, {
|
|
73
|
+
get(target, prop) {
|
|
74
|
+
if (prop === "argtypes") return argtypes;
|
|
75
|
+
if (prop === "restype") return restype;
|
|
76
|
+
if (prop === "errcheck") return cachedFunc ? cachedFunc.errcheck : undefined;
|
|
77
|
+
if (prop === "callAsync") {
|
|
92
78
|
if (restype === undefined) {
|
|
93
79
|
throw new Error(`Function ${name}: restype not set`);
|
|
94
80
|
}
|
|
95
|
-
|
|
81
|
+
if (!cachedFunc) {
|
|
82
|
+
cachedFunc = cdll.func(name, restype, argtypes);
|
|
83
|
+
}
|
|
84
|
+
return cachedFunc.callAsync;
|
|
85
|
+
}
|
|
86
|
+
return target[prop];
|
|
87
|
+
},
|
|
88
|
+
set(target, prop, value) {
|
|
89
|
+
if (prop === "argtypes") {
|
|
90
|
+
argtypes.splice(0, argtypes.length, ...value);
|
|
91
|
+
cachedFunc = null; // Invalidate cache
|
|
92
|
+
return true;
|
|
96
93
|
}
|
|
97
|
-
|
|
94
|
+
if (prop === "restype") {
|
|
95
|
+
restype = value;
|
|
96
|
+
cachedFunc = null; // Invalidate cache
|
|
97
|
+
return true;
|
|
98
|
+
}
|
|
99
|
+
if (prop === "errcheck") {
|
|
100
|
+
if (!cachedFunc) {
|
|
101
|
+
if (restype === undefined) {
|
|
102
|
+
throw new Error(`Function ${name}: restype not set`);
|
|
103
|
+
}
|
|
104
|
+
cachedFunc = cdll.func(name, restype, argtypes);
|
|
105
|
+
}
|
|
106
|
+
cachedFunc.errcheck = value;
|
|
107
|
+
return true;
|
|
108
|
+
}
|
|
109
|
+
target[prop] = value;
|
|
98
110
|
return true;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
},
|
|
103
|
-
});
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
/**
|
|
108
|
-
* Wrapper conveniente per CDLL (come in Python ctypes)
|
|
109
|
-
*/
|
|
110
|
-
class CDLL {
|
|
111
|
-
constructor(libPath, options = {}) {
|
|
112
|
-
this._lib = new Library(libPath);
|
|
113
|
-
// Use LRU cache to prevent unbounded memory growth
|
|
114
|
-
const cacheSize = options.cacheSize ?? 1000;
|
|
115
|
-
this._cache = new LRUCache(cacheSize);
|
|
116
|
-
|
|
117
|
-
// Return a proxy to enable Python-like syntax: libc.abs.argtypes = [...]; libc.abs.restype = ...; libc.abs(...)
|
|
118
|
-
return new Proxy(this, {
|
|
119
|
-
get(target, prop, receiver) {
|
|
120
|
-
// Allow access to existing properties/methods
|
|
121
|
-
if (prop in target || typeof prop !== "string") {
|
|
122
|
-
return Reflect.get(target, prop, receiver);
|
|
123
|
-
}
|
|
124
|
-
// Assume it's a function name from the library
|
|
125
|
-
return new FunctionWrapper(target, prop);
|
|
126
|
-
},
|
|
127
|
-
});
|
|
111
|
+
},
|
|
112
|
+
});
|
|
113
|
+
}
|
|
128
114
|
}
|
|
129
115
|
|
|
130
116
|
/**
|
|
131
|
-
*
|
|
132
|
-
* @param {string} name - Nome della funzione
|
|
133
|
-
* @param {Function|number|CType} returnType - Tipo di ritorno (SimpleCData class, CType value, o CType)
|
|
134
|
-
* @param {Array<Function|number|CType>} argTypes - Tipi degli argomenti
|
|
135
|
-
* @param {Object} [options] - Opzioni aggiuntive (es. { abi: 'stdcall' })
|
|
136
|
-
* @returns {Function} Funzione callable
|
|
117
|
+
* Wrapper conveniente per CDLL (come in Python ctypes)
|
|
137
118
|
*/
|
|
138
|
-
|
|
139
|
-
|
|
119
|
+
class CDLL {
|
|
120
|
+
constructor(libPath, options = {}) {
|
|
121
|
+
this._lib = new Library(libPath);
|
|
122
|
+
// Use LRU cache to prevent unbounded memory growth
|
|
123
|
+
const cacheSize = options.cacheSize ?? 1000;
|
|
124
|
+
this._cache = new LRUCache(cacheSize);
|
|
125
|
+
// Cache for FunctionWrapper instances (Python-like syntax)
|
|
126
|
+
this._funcWrapperCache = new Map();
|
|
140
127
|
|
|
141
|
-
|
|
142
|
-
return this
|
|
128
|
+
// Return a proxy to enable Python-like syntax: libc.abs.argtypes = [...]; libc.abs.restype = ...; libc.abs(...)
|
|
129
|
+
return new Proxy(this, {
|
|
130
|
+
get(target, prop, receiver) {
|
|
131
|
+
// Allow access to existing properties/methods
|
|
132
|
+
if (prop in target || typeof prop !== "string") {
|
|
133
|
+
return Reflect.get(target, prop, receiver);
|
|
134
|
+
}
|
|
135
|
+
// Check if we already have a FunctionWrapper for this function name
|
|
136
|
+
if (target._funcWrapperCache.has(prop)) {
|
|
137
|
+
return target._funcWrapperCache.get(prop);
|
|
138
|
+
}
|
|
139
|
+
// Create and cache a new FunctionWrapper
|
|
140
|
+
const wrapper = new FunctionWrapper(target, prop);
|
|
141
|
+
target._funcWrapperCache.set(prop, wrapper);
|
|
142
|
+
return wrapper;
|
|
143
|
+
},
|
|
144
|
+
});
|
|
143
145
|
}
|
|
144
146
|
|
|
145
|
-
|
|
147
|
+
/**
|
|
148
|
+
* Ottiene una funzione dalla libreria
|
|
149
|
+
* @param {string} name - Nome della funzione
|
|
150
|
+
* @param {Function|number|CType} returnType - Tipo di ritorno (SimpleCData class, CType value, o CType)
|
|
151
|
+
* @param {Array<Function|number|CType>} argTypes - Tipi degli argomenti
|
|
152
|
+
* @param {Object} [options] - Opzioni aggiuntive (es. { abi: 'stdcall' })
|
|
153
|
+
* @returns {Function} Funzione callable
|
|
154
|
+
*/
|
|
155
|
+
func(name, returnType, argTypes = [], options = {}) {
|
|
156
|
+
const cacheKey = `${name}:${returnType}:${argTypes.join(",")}`;
|
|
146
157
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
// =========================================================================
|
|
158
|
+
if (this._cache.has(cacheKey)) {
|
|
159
|
+
return this._cache.get(cacheKey);
|
|
160
|
+
}
|
|
151
161
|
|
|
152
|
-
|
|
162
|
+
const ffiFunc = this._lib.func(name, _toNativeType(returnType, native), _toNativeTypes(argTypes, native), options);
|
|
153
163
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
const typeName = t._type;
|
|
159
|
-
return typeName !== native.CType.POINTER && typeName !== native.CType.STRING && typeName !== native.CType.WSTRING;
|
|
160
|
-
}
|
|
161
|
-
return false;
|
|
162
|
-
});
|
|
164
|
+
// =========================================================================
|
|
165
|
+
// OPTIMIZATION: Create specialized wrapper based on argument types
|
|
166
|
+
// For primitive-only args, bypass the processing loop entirely
|
|
167
|
+
// =========================================================================
|
|
163
168
|
|
|
164
|
-
|
|
169
|
+
const argCount = argTypes.length;
|
|
165
170
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
callMethod = function (a0) {
|
|
176
|
-
return ffiFunc.call(a0);
|
|
177
|
-
};
|
|
178
|
-
break;
|
|
179
|
-
case 2:
|
|
180
|
-
callMethod = function (a0, a1) {
|
|
181
|
-
return ffiFunc.call(a0, a1);
|
|
182
|
-
};
|
|
183
|
-
break;
|
|
184
|
-
case 3:
|
|
185
|
-
callMethod = function (a0, a1, a2) {
|
|
186
|
-
return ffiFunc.call(a0, a1, a2);
|
|
187
|
-
};
|
|
188
|
-
break;
|
|
189
|
-
case 4:
|
|
190
|
-
callMethod = function (a0, a1, a2, a3) {
|
|
191
|
-
return ffiFunc.call(a0, a1, a2, a3);
|
|
192
|
-
};
|
|
193
|
-
break;
|
|
194
|
-
default:
|
|
195
|
-
// Fallback for many args
|
|
196
|
-
callMethod = function (...args) {
|
|
197
|
-
return ffiFunc.call(...args);
|
|
198
|
-
};
|
|
199
|
-
}
|
|
200
|
-
} else {
|
|
201
|
-
// SLOW PATH: Has buffer/struct args - need to extract _buffer
|
|
202
|
-
callMethod = function (...args) {
|
|
203
|
-
const processedArgs = [];
|
|
171
|
+
// Check if all args are primitive types (no structs/buffers that need _buffer extraction)
|
|
172
|
+
const allPrimitive = argTypes.every((t) => {
|
|
173
|
+
if (typeof t === "function" && t._isSimpleCData) {
|
|
174
|
+
// SimpleCData types that are NOT pointers are primitive
|
|
175
|
+
const typeName = t._type;
|
|
176
|
+
return typeName !== native.CType.POINTER && typeName !== native.CType.STRING && typeName !== native.CType.WSTRING;
|
|
177
|
+
}
|
|
178
|
+
return false;
|
|
179
|
+
});
|
|
204
180
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
181
|
+
let callMethod;
|
|
182
|
+
|
|
183
|
+
if (argCount === 0) {
|
|
184
|
+
// FAST PATH: No declared arguments - but still support variadic
|
|
185
|
+
callMethod = function (...args) {
|
|
186
|
+
if (args.length === 0) {
|
|
187
|
+
return ffiFunc.call();
|
|
188
|
+
}
|
|
189
|
+
// Variadic: pass all args directly
|
|
190
|
+
return ffiFunc.call(...args);
|
|
191
|
+
};
|
|
192
|
+
} else if (allPrimitive) {
|
|
193
|
+
// FAST PATH: All primitive args - use rest args to support variadic
|
|
194
|
+
callMethod = function (...args) {
|
|
195
|
+
return ffiFunc.call(...args);
|
|
196
|
+
};
|
|
197
|
+
} else {
|
|
198
|
+
// SLOW PATH: Has buffer/struct args - need to extract _buffer
|
|
199
|
+
callMethod = function (...args) {
|
|
200
|
+
const processedArgs = [];
|
|
201
|
+
|
|
202
|
+
for (let i = 0; i < args.length; i++) {
|
|
203
|
+
const arg = args[i];
|
|
204
|
+
// Check for _buffer FIRST (handles Proxy-wrapped structs)
|
|
205
|
+
// This avoids calling Buffer.isBuffer() on Proxy which can cause issues
|
|
206
|
+
if (arg && typeof arg === "object") {
|
|
207
|
+
// Check for struct proxy FIRST - accessing _buffer on Proxy is safe
|
|
208
|
+
// but Buffer.isBuffer(proxy) can cause hangs
|
|
209
|
+
if (arg._buffer !== undefined && Buffer.isBuffer(arg._buffer)) {
|
|
210
|
+
// Struct proxy or object with _buffer
|
|
211
|
+
processedArgs.push(arg._buffer);
|
|
212
|
+
} else if (Buffer.isBuffer(arg)) {
|
|
213
|
+
// Already a buffer, use directly
|
|
214
|
+
processedArgs.push(arg);
|
|
215
|
+
} else {
|
|
216
|
+
// Other object, pass as-is
|
|
217
|
+
processedArgs.push(arg);
|
|
218
|
+
}
|
|
219
|
+
} else {
|
|
220
|
+
// Primitive value (number, string, bigint, null, undefined)
|
|
217
221
|
processedArgs.push(arg);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
return ffiFunc.call(...processedArgs);
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// =========================================================================
|
|
230
|
+
// ASYNC WRAPPER: same argument processing, but calls callAsync
|
|
231
|
+
// Returns a Promise instead of the result directly
|
|
232
|
+
// =========================================================================
|
|
233
|
+
|
|
234
|
+
let asyncCallMethod;
|
|
235
|
+
|
|
236
|
+
if (argCount === 0) {
|
|
237
|
+
asyncCallMethod = function (...args) {
|
|
238
|
+
if (args.length === 0) {
|
|
239
|
+
return ffiFunc.callAsync();
|
|
240
|
+
}
|
|
241
|
+
// Variadic: pass all args directly
|
|
242
|
+
return ffiFunc.callAsync(...args);
|
|
243
|
+
};
|
|
244
|
+
} else if (allPrimitive) {
|
|
245
|
+
asyncCallMethod = function (...args) {
|
|
246
|
+
return ffiFunc.callAsync(...args);
|
|
247
|
+
};
|
|
248
|
+
} else {
|
|
249
|
+
asyncCallMethod = function (...args) {
|
|
250
|
+
const processedArgs = [];
|
|
251
|
+
|
|
252
|
+
for (let i = 0; i < args.length; i++) {
|
|
253
|
+
const arg = args[i];
|
|
254
|
+
if (arg && typeof arg === "object") {
|
|
255
|
+
if (arg._buffer !== undefined && Buffer.isBuffer(arg._buffer)) {
|
|
256
|
+
processedArgs.push(arg._buffer);
|
|
257
|
+
} else if (Buffer.isBuffer(arg)) {
|
|
258
|
+
processedArgs.push(arg);
|
|
259
|
+
} else {
|
|
260
|
+
processedArgs.push(arg);
|
|
261
|
+
}
|
|
218
262
|
} else {
|
|
219
|
-
// Other object, pass as-is
|
|
220
263
|
processedArgs.push(arg);
|
|
221
264
|
}
|
|
222
|
-
} else {
|
|
223
|
-
// Primitive value (number, string, bigint, null, undefined)
|
|
224
|
-
processedArgs.push(arg);
|
|
225
265
|
}
|
|
226
|
-
}
|
|
227
266
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
267
|
+
return ffiFunc.callAsync(...processedArgs);
|
|
268
|
+
};
|
|
269
|
+
}
|
|
231
270
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
271
|
+
// Aggiungi metadata come proprietà non-enumerable per non interferire
|
|
272
|
+
Object.defineProperties(callMethod, {
|
|
273
|
+
funcName: { value: name },
|
|
274
|
+
address: { value: ffiFunc.address },
|
|
275
|
+
_ffi: { value: ffiFunc },
|
|
276
|
+
callAsync: { value: asyncCallMethod, writable: false, enumerable: false, configurable: false },
|
|
277
|
+
// Esponi errcheck come setter/getter
|
|
278
|
+
errcheck: {
|
|
279
|
+
get() {
|
|
280
|
+
return ffiFunc._errcheck;
|
|
281
|
+
},
|
|
282
|
+
set(callback) {
|
|
283
|
+
ffiFunc._errcheck = callback;
|
|
284
|
+
ffiFunc.setErrcheck(callback);
|
|
285
|
+
},
|
|
286
|
+
enumerable: false,
|
|
287
|
+
configurable: true,
|
|
245
288
|
},
|
|
246
|
-
|
|
247
|
-
configurable: true,
|
|
248
|
-
},
|
|
249
|
-
});
|
|
289
|
+
});
|
|
250
290
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
291
|
+
this._cache.set(cacheKey, callMethod);
|
|
292
|
+
return callMethod;
|
|
293
|
+
}
|
|
254
294
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
295
|
+
/**
|
|
296
|
+
* Ottiene l'indirizzo di un simbolo
|
|
297
|
+
* @param {string} name - Nome del simbolo
|
|
298
|
+
* @returns {BigInt} Indirizzo del simbolo
|
|
299
|
+
*/
|
|
300
|
+
symbol(name) {
|
|
301
|
+
return this._lib.symbol(name);
|
|
302
|
+
}
|
|
263
303
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
304
|
+
/**
|
|
305
|
+
* Crea un callback JS chiamabile da C
|
|
306
|
+
* @param {Function} fn - Funzione JavaScript
|
|
307
|
+
* @param {Function|number|CType} returnType - Tipo di ritorno (SimpleCData class, CType value, o CType)
|
|
308
|
+
* @param {Array<Function|number|CType>} argTypes - Tipi degli argomenti
|
|
309
|
+
* @returns {Object} Oggetto callback con proprietà pointer e metodi
|
|
310
|
+
*/
|
|
311
|
+
callback(fn, returnType, argTypes = []) {
|
|
312
|
+
return this._lib.callback(_toNativeType(returnType, native), _toNativeTypes(argTypes, native), fn);
|
|
313
|
+
}
|
|
274
314
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
315
|
+
/**
|
|
316
|
+
* Chiude la libreria
|
|
317
|
+
*/
|
|
318
|
+
close() {
|
|
319
|
+
this._lib.close();
|
|
320
|
+
this._cache.clear();
|
|
321
|
+
}
|
|
282
322
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
323
|
+
get path() {
|
|
324
|
+
return this._lib.path;
|
|
325
|
+
}
|
|
286
326
|
|
|
287
|
-
|
|
288
|
-
|
|
327
|
+
get loaded() {
|
|
328
|
+
return this._lib.loaded;
|
|
329
|
+
}
|
|
289
330
|
}
|
|
290
|
-
}
|
|
291
331
|
|
|
292
|
-
/**
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
class WinDLL extends CDLL {
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
332
|
+
/**
|
|
333
|
+
* WinDLL - come CDLL ma con stdcall di default (per Windows)
|
|
334
|
+
*/
|
|
335
|
+
class WinDLL extends CDLL {
|
|
336
|
+
func(name, returnType, argTypes = [], options = {}) {
|
|
337
|
+
return super.func(name, returnType, argTypes, {
|
|
338
|
+
abi: "stdcall",
|
|
339
|
+
...options,
|
|
340
|
+
});
|
|
341
|
+
}
|
|
301
342
|
}
|
|
302
|
-
}
|
|
303
343
|
|
|
304
344
|
return { FunctionWrapper, CDLL, WinDLL };
|
|
305
345
|
}
|
package/lib/core/types.js
CHANGED
|
@@ -88,6 +88,13 @@ export function _toNativeType(type, native) {
|
|
|
88
88
|
return type._type;
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
+
// POINTER types: return CType.POINTER (11)
|
|
92
|
+
// POINTER(baseType) returns an object with _pointerTo property
|
|
93
|
+
if (type && typeof type === "object" && type._pointerTo !== undefined) {
|
|
94
|
+
// All pointer types are passed as generic pointers to FFI
|
|
95
|
+
return native.CType.POINTER;
|
|
96
|
+
}
|
|
97
|
+
|
|
91
98
|
// Structure/Union classes: pass through unchanged
|
|
92
99
|
// These are handled specially by the FFI layer
|
|
93
100
|
if (typeof type === "function" && type.prototype) {
|
package/lib/index.d.ts
CHANGED
|
@@ -79,6 +79,8 @@ export type ErrcheckCallback = (result: any, func: CallableFunction, args: any[]
|
|
|
79
79
|
/** FFI function wrapper */
|
|
80
80
|
export interface FFIFunction {
|
|
81
81
|
(...args: any[]): any;
|
|
82
|
+
/** Async version: executes the native call on a worker thread, returns a Promise */
|
|
83
|
+
callAsync(...args: any[]): Promise<any>;
|
|
82
84
|
readonly funcName: string;
|
|
83
85
|
readonly address: bigint;
|
|
84
86
|
errcheck: ErrcheckCallback | null;
|
|
@@ -87,11 +89,23 @@ export interface FFIFunction {
|
|
|
87
89
|
/** CDLL - C calling convention library */
|
|
88
90
|
export class CDLL {
|
|
89
91
|
constructor(path: string | null);
|
|
90
|
-
func(name: string, returnType: AnyType, argTypes?: AnyType[], options?: FunctionOptions): CallableFunction & { errcheck: ErrcheckCallback | null };
|
|
92
|
+
func(name: string, returnType: AnyType, argTypes?: AnyType[], options?: FunctionOptions): CallableFunction & { callAsync(...args: any[]): Promise<any>; errcheck: ErrcheckCallback | null };
|
|
91
93
|
symbol(name: string): bigint;
|
|
92
94
|
close(): void;
|
|
93
95
|
readonly path: string;
|
|
94
96
|
readonly loaded: boolean;
|
|
97
|
+
/** Python-like function access: lib.FuncName returns a FunctionWrapper */
|
|
98
|
+
[funcName: string]: FunctionWrapper | any;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/** FunctionWrapper for Python-like argtypes/restype syntax */
|
|
102
|
+
export interface FunctionWrapper {
|
|
103
|
+
(...args: any[]): any;
|
|
104
|
+
/** Async version: executes the native call on a worker thread, returns a Promise */
|
|
105
|
+
callAsync(...args: any[]): Promise<any>;
|
|
106
|
+
argtypes: AnyType[];
|
|
107
|
+
restype: AnyType;
|
|
108
|
+
errcheck: ErrcheckCallback | null;
|
|
95
109
|
}
|
|
96
110
|
|
|
97
111
|
/** WinDLL - stdcall calling convention library (Windows) */
|
|
@@ -326,6 +340,7 @@ export function bitfield(baseType: AnyType, bits: number): BitFieldDef;
|
|
|
326
340
|
export function byref(obj: Buffer | SimpleCDataInstance | { _buffer: Buffer }): Buffer;
|
|
327
341
|
export function cast(ptr: Buffer | bigint, targetType: AnyType | StructDef): Buffer | { [key: string]: any };
|
|
328
342
|
export function POINTER(baseType: AnyType | StructDef): PointerTypeDef;
|
|
343
|
+
export function pointer(obj: SimpleCDataInstance | { _buffer: Buffer }): SimpleCDataInstance & { contents: any; [index: number]: any };
|
|
329
344
|
|
|
330
345
|
// Error handling
|
|
331
346
|
export function get_errno(): number;
|
|
@@ -343,7 +358,7 @@ export function WinError(code?: number): Error & { winerror: number };
|
|
|
343
358
|
export interface SimpleCDataConstructor {
|
|
344
359
|
new (value?: any): SimpleCDataInstance;
|
|
345
360
|
readonly _size: number;
|
|
346
|
-
readonly _type: number;
|
|
361
|
+
readonly _type: number; // CType numeric value from native module
|
|
347
362
|
readonly _isSimpleCData: true;
|
|
348
363
|
_reader(buf: Buffer, offset: number): any;
|
|
349
364
|
_writer(buf: Buffer, offset: number, value: any): void;
|
|
@@ -385,6 +400,17 @@ export const c_size_t: SimpleCDataConstructor;
|
|
|
385
400
|
export const c_long: SimpleCDataConstructor;
|
|
386
401
|
export const c_ulong: SimpleCDataConstructor;
|
|
387
402
|
|
|
403
|
+
// Python-compatible aliases
|
|
404
|
+
export const c_byte: SimpleCDataConstructor;
|
|
405
|
+
export const c_ubyte: SimpleCDataConstructor;
|
|
406
|
+
export const c_short: SimpleCDataConstructor;
|
|
407
|
+
export const c_ushort: SimpleCDataConstructor;
|
|
408
|
+
export const c_longlong: SimpleCDataConstructor;
|
|
409
|
+
export const c_ulonglong: SimpleCDataConstructor;
|
|
410
|
+
|
|
411
|
+
/** SimpleCData base class for creating custom simple types */
|
|
412
|
+
export const SimpleCData: SimpleCDataConstructor;
|
|
413
|
+
|
|
388
414
|
// =============================================================================
|
|
389
415
|
// Constants
|
|
390
416
|
// =============================================================================
|