koffi 2.4.1 → 2.4.2
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/CHANGELOG.md +12 -2
- package/build/2.4.2/koffi_darwin_arm64/koffi.node +0 -0
- package/build/{2.4.1 → 2.4.2}/koffi_darwin_x64/koffi.node +0 -0
- package/build/{2.4.1 → 2.4.2}/koffi_freebsd_arm64/koffi.node +0 -0
- package/build/2.4.2/koffi_freebsd_ia32/koffi.node +0 -0
- package/build/{2.4.1 → 2.4.2}/koffi_freebsd_x64/koffi.node +0 -0
- package/build/{2.4.1 → 2.4.2}/koffi_linux_arm32hf/koffi.node +0 -0
- package/build/{2.4.1 → 2.4.2}/koffi_linux_arm64/koffi.node +0 -0
- package/build/{2.4.1 → 2.4.2}/koffi_linux_ia32/koffi.node +0 -0
- package/build/{2.4.1 → 2.4.2}/koffi_linux_riscv64hf64/koffi.node +0 -0
- package/build/{2.4.1 → 2.4.2}/koffi_linux_x64/koffi.node +0 -0
- package/build/2.4.2/koffi_openbsd_ia32/koffi.node +0 -0
- package/build/{2.4.1 → 2.4.2}/koffi_openbsd_x64/koffi.node +0 -0
- package/build/2.4.2/koffi_win32_arm64/koffi.node +0 -0
- package/build/{2.4.1 → 2.4.2}/koffi_win32_ia32/koffi.node +0 -0
- package/build/{2.4.1 → 2.4.2}/koffi_win32_x64/koffi.node +0 -0
- package/doc/functions.md +73 -4
- package/package.json +2 -2
- package/src/koffi/src/ffi.cc +4 -9
- package/src/koffi/src/parser.cc +1 -1
- package/src/koffi/src/util.cc +4 -0
- package/build/2.4.1/koffi_darwin_arm64/koffi.node +0 -0
- package/build/2.4.1/koffi_freebsd_ia32/koffi.node +0 -0
- package/build/2.4.1/koffi_openbsd_ia32/koffi.node +0 -0
- package/build/2.4.1/koffi_win32_arm64/koffi.node +0 -0
- /package/build/{2.4.1 → 2.4.2}/koffi_win32_arm64/koffi.exp +0 -0
- /package/build/{2.4.1 → 2.4.2}/koffi_win32_arm64/koffi.lib +0 -0
- /package/build/{2.4.1 → 2.4.2}/koffi_win32_ia32/koffi.exp +0 -0
- /package/build/{2.4.1 → 2.4.2}/koffi_win32_ia32/koffi.lib +0 -0
- /package/build/{2.4.1 → 2.4.2}/koffi_win32_x64/koffi.exp +0 -0
- /package/build/{2.4.1 → 2.4.2}/koffi_win32_x64/koffi.lib +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -4,12 +4,22 @@
|
|
|
4
4
|
|
|
5
5
|
### Koffi 2.4
|
|
6
6
|
|
|
7
|
+
#### Koffi 2.4.2
|
|
8
|
+
|
|
9
|
+
**Main changes:**
|
|
10
|
+
|
|
11
|
+
- Support calling variadic function pointers
|
|
12
|
+
|
|
13
|
+
**Other changes:**
|
|
14
|
+
|
|
15
|
+
- Add documentation for function pointers
|
|
16
|
+
|
|
7
17
|
#### Koffi 2.4.1
|
|
8
18
|
|
|
9
19
|
**Main changes:**
|
|
10
20
|
|
|
11
|
-
- Support decoding pointers to callable functions
|
|
12
|
-
- Support calling function pointers with [koffi.call()]
|
|
21
|
+
- Support [decoding function pointers](functions.md#decode-pointer-to-function) to callable functions
|
|
22
|
+
- Support calling function pointers with [koffi.call()](functions.md#call-pointer-directly)
|
|
13
23
|
- Deprecate `koffi.callback` in favor of `koffi.proto`
|
|
14
24
|
|
|
15
25
|
**Other changes:**
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/doc/functions.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Function calls
|
|
2
2
|
|
|
3
3
|
## Loading libraries
|
|
4
4
|
|
|
@@ -89,7 +89,7 @@ const MessageBoxA_1 = lib.stdcall('MessageBoxA', 'int', ['void *', 'str', 'str',
|
|
|
89
89
|
const MessageBoxA_2 = lib.func('int __stdcall MessageBoxA(void *hwnd, str text, str caption, uint type)');
|
|
90
90
|
```
|
|
91
91
|
|
|
92
|
-
##
|
|
92
|
+
## Call types
|
|
93
93
|
|
|
94
94
|
### Synchronous calls
|
|
95
95
|
|
|
@@ -137,8 +137,77 @@ You can easily convert this callback-style async function to a promise-based ver
|
|
|
137
137
|
|
|
138
138
|
Variadic functions cannot be called asynchronously.
|
|
139
139
|
|
|
140
|
-
|
|
141
|
-
|
|
140
|
+
```{note}
|
|
142
141
|
Asynchronous functions run on worker threads. You need to deal with thread safety issues if you share data between threads.
|
|
143
142
|
|
|
144
143
|
Callbacks must be called from the main thread, or more precisely from the same thread as the V8 intepreter. Calling a callback from another thread is undefined behavior, and will likely lead to a crash or a big mess. You've been warned!
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## Function pointers
|
|
147
|
+
|
|
148
|
+
*New in Koffi 2.4*
|
|
149
|
+
|
|
150
|
+
You can call a function pointer in two ways:
|
|
151
|
+
|
|
152
|
+
- Directly call the function pointer with `koffi.call(ptr, type, ...)`
|
|
153
|
+
- Decode the function pointer to an actual function with `koffi.decode(ptr, type)`
|
|
154
|
+
|
|
155
|
+
The example below shows how to call an `int (*)(int, int)` C function pointer both ways, based on the following native C library:
|
|
156
|
+
|
|
157
|
+
```c
|
|
158
|
+
typedef int BinaryIntFunc(int a, int b);
|
|
159
|
+
|
|
160
|
+
static int AddInt(int a, int b) { return a + b; }
|
|
161
|
+
static int SubstractInt(int a, int b) { return a - b; }
|
|
162
|
+
|
|
163
|
+
BinaryIntFunc *GetBinaryIntFunction(const char *type)
|
|
164
|
+
{
|
|
165
|
+
if (!strcmp(type, "add")) {
|
|
166
|
+
return AddInt;
|
|
167
|
+
} else if (!strcmp(type, "substract")) {
|
|
168
|
+
return SubstractInt;
|
|
169
|
+
} else {
|
|
170
|
+
return NULL;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### Call pointer directly
|
|
176
|
+
|
|
177
|
+
Use `koffi.call(ptr, type, ...)` to call a function pointer. The first two arguments are the pointer itself and the type of the function you are trying to call (declared with `koffi.proto()` as shown below), and the remaining arguments are used for the call.
|
|
178
|
+
|
|
179
|
+
```js
|
|
180
|
+
// Declare function type
|
|
181
|
+
const BinaryIntFunc = koffi.proto('int BinaryIntFunc(int a, int b)');
|
|
182
|
+
|
|
183
|
+
const GetBinaryIntFunction = lib.func('BinaryIntFunc *GetBinaryIntFunction(const char *name)');
|
|
184
|
+
|
|
185
|
+
const add_ptr = GetBinaryIntFunction('add');
|
|
186
|
+
const substract_ptr = GetBinaryIntFunction('substract');
|
|
187
|
+
|
|
188
|
+
let sum = koffi.call(add_ptr, BinaryIntFunc, 4, 5);
|
|
189
|
+
let delta = koffi.call(substract_ptr, BinaryIntFunc, 100, 58);
|
|
190
|
+
|
|
191
|
+
console.log(sum, delta); // Prints 9 and 42
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### Decode pointer to function
|
|
195
|
+
|
|
196
|
+
Use `koffi.decode(ptr, type)` to get back a JS function, which you can then use like any other Koffi function.
|
|
197
|
+
|
|
198
|
+
This method also allows you to perform an [asynchronous call](#asynchronous-calls) with the async member of the decoded function.
|
|
199
|
+
|
|
200
|
+
```js
|
|
201
|
+
// Declare function type
|
|
202
|
+
const BinaryIntFunc = koffi.proto('int BinaryIntFunc(int a, int b)');
|
|
203
|
+
|
|
204
|
+
const GetBinaryIntFunction = lib.func('BinaryIntFunc *GetBinaryIntFunction(const char *name)');
|
|
205
|
+
|
|
206
|
+
const add = koffi.decode(GetBinaryIntFunction('add'), BinaryIntFunc);
|
|
207
|
+
const substract = koffi.decode(GetBinaryIntFunction('substract'), BinaryIntFunc);
|
|
208
|
+
|
|
209
|
+
let sum = add(4, 5);
|
|
210
|
+
let delta = substract(100, 58);
|
|
211
|
+
|
|
212
|
+
console.log(sum, delta); // Prints 9 and 42
|
|
213
|
+
```
|
package/package.json
CHANGED
package/src/koffi/src/ffi.cc
CHANGED
|
@@ -895,7 +895,7 @@ static bool ParseClassicFunction(Napi::Env env, Napi::String name, Napi::Value r
|
|
|
895
895
|
if (!param.type)
|
|
896
896
|
return false;
|
|
897
897
|
if (!CanPassType(param.type, param.directions)) {
|
|
898
|
-
ThrowError<Napi::TypeError>(env, "Type %1 cannot be used as a parameter
|
|
898
|
+
ThrowError<Napi::TypeError>(env, "Type %1 cannot be used as a parameter", param.type->name);
|
|
899
899
|
return false;
|
|
900
900
|
}
|
|
901
901
|
if (func->parameters.len >= MaxParameters) {
|
|
@@ -942,11 +942,6 @@ static Napi::Value CreateFunctionType(const Napi::CallbackInfo &info)
|
|
|
942
942
|
return env.Null();
|
|
943
943
|
}
|
|
944
944
|
|
|
945
|
-
if (func->variadic) {
|
|
946
|
-
LogError("Variadic callbacks are not supported");
|
|
947
|
-
return env.Null();
|
|
948
|
-
}
|
|
949
|
-
|
|
950
945
|
if (!AnalyseFunction(env, instance, func))
|
|
951
946
|
return env.Null();
|
|
952
947
|
|
|
@@ -1310,7 +1305,7 @@ static Napi::Value TranslateVariadicCall(const FunctionInfo *func, void *native,
|
|
|
1310
1305
|
if (RG_UNLIKELY(!param.type))
|
|
1311
1306
|
return env.Null();
|
|
1312
1307
|
if (RG_UNLIKELY(!CanPassType(param.type, param.directions))) {
|
|
1313
|
-
ThrowError<Napi::TypeError>(env, "Type %1 cannot be used as a parameter
|
|
1308
|
+
ThrowError<Napi::TypeError>(env, "Type %1 cannot be used as a parameter", param.type->name);
|
|
1314
1309
|
return env.Null();
|
|
1315
1310
|
}
|
|
1316
1311
|
if (RG_UNLIKELY(copy.parameters.len >= MaxParameters)) {
|
|
@@ -2084,9 +2079,9 @@ static Napi::Value CallPointerSync(const Napi::CallbackInfo &info)
|
|
|
2084
2079
|
}
|
|
2085
2080
|
|
|
2086
2081
|
const FunctionInfo *proto = type->ref.proto;
|
|
2087
|
-
RG_ASSERT(!proto->variadic);
|
|
2088
2082
|
|
|
2089
|
-
return
|
|
2083
|
+
return proto->variadic ? TranslateVariadicCall(proto, ptr, info)
|
|
2084
|
+
: TranslateNormalCall(proto, ptr, info);
|
|
2090
2085
|
}
|
|
2091
2086
|
|
|
2092
2087
|
extern "C" void RelayCallback(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegisters *out_reg)
|
package/src/koffi/src/parser.cc
CHANGED
|
@@ -75,7 +75,7 @@ bool PrototypeParser::Parse(const char *str, FunctionInfo *out_func)
|
|
|
75
75
|
param.type = ParseType();
|
|
76
76
|
|
|
77
77
|
if (!CanPassType(param.type, param.directions)) {
|
|
78
|
-
MarkError("Type %1 cannot be used as a parameter
|
|
78
|
+
MarkError("Type %1 cannot be used as a parameter", param.type->name);
|
|
79
79
|
return false;
|
|
80
80
|
}
|
|
81
81
|
if (out_func->parameters.len >= MaxParameters) {
|
package/src/koffi/src/util.cc
CHANGED
|
@@ -371,6 +371,8 @@ bool CanPassType(const TypeInfo *type, int directions)
|
|
|
371
371
|
return false;
|
|
372
372
|
if (type->primitive == PrimitiveKind::Prototype)
|
|
373
373
|
return false;
|
|
374
|
+
if (type->primitive == PrimitiveKind::Callback && type->ref.proto->variadic)
|
|
375
|
+
return false;
|
|
374
376
|
|
|
375
377
|
return true;
|
|
376
378
|
}
|
|
@@ -394,6 +396,8 @@ bool CanStoreType(const TypeInfo *type)
|
|
|
394
396
|
return false;
|
|
395
397
|
if (type->primitive == PrimitiveKind::Prototype)
|
|
396
398
|
return false;
|
|
399
|
+
if (type->primitive == PrimitiveKind::Callback && type->ref.proto->variadic)
|
|
400
|
+
return false;
|
|
397
401
|
|
|
398
402
|
return true;
|
|
399
403
|
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|