koffi 2.6.12 → 2.7.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/CHANGELOG.md CHANGED
@@ -2,6 +2,14 @@
2
2
 
3
3
  ## Version history
4
4
 
5
+ ### Koffi 2.7
6
+
7
+ #### Koffi 2.7.0 (2023-12-21)
8
+
9
+ - Support alternative [callback calling convention](callbacks.md#callback-types) in classic syntax
10
+ - Change syntax for [calling conventions](functions.md#calling-conventions) with classic syntax
11
+ - Drop unused "internal" property from Koffi
12
+
5
13
  ### Koffi 2.6
6
14
 
7
15
  #### Koffi 2.6.12 (2023-12-11)
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/callbacks.md CHANGED
@@ -8,6 +8,8 @@ The function `koffi.proto()` was introduced in Koffi 2.4, it was called `koffi.c
8
8
 
9
9
  ## Callback types
10
10
 
11
+ *Changed in Koffi 2.7*
12
+
11
13
  In order to pass a JS function to a C function expecting a callback, you must first create a callback type with the expected return type and parameters. The syntax is similar to the one used to load functions from a shared library.
12
14
 
13
15
  ```js
@@ -21,6 +23,23 @@ const ExampleCallback = koffi.proto('ExampleCallback', 'void', ['int']);
21
23
  const AddDoubleFloat = koffi.proto('double AddDoubleFloat(double d, float f)');
22
24
  ```
23
25
 
26
+ For alternative [calling conventions](functions.md#calling-conventions) (such as `stdcall` on Windows x86 32-bit), you can specify as the first argument with the classic syntax, or after the return type in prototype strings, like this:
27
+
28
+ ```js
29
+ const HANDLE = koffi.pointer('HANDLE', koffi.opaque());
30
+ const HWND = koffi.alias('HWND', HANDLE);
31
+
32
+ // These two declarations work the same, and use the __stdcall convention on Windows x86
33
+ const EnumWindowsProc = koffi.proto('bool __stdcall EnumWindowsProc (HWND hwnd, long lParam)');
34
+ const EnumWindowsProc = koffi.proto('__stdcall', 'EnumWindowsProc', 'bool', ['HWND', 'long']);
35
+ ```
36
+
37
+ ```{warning}
38
+ You have to make sure you **get the calling convention right** (such as specifying __stdcall for a Windows API callback), or your code will crash on Windows 32-bit.
39
+
40
+ Before Koffi 2.7, it was *impossible to use an alternative callback calling convention with the classic syntax*. Use a prototype string or *upgrade to Koffi 2.7* to solve this limitation.
41
+ ```
42
+
24
43
  Once your callback type is declared, you can use a pointer to it in struct definitions, as function parameters and/or return types, or to call/decode function pointers.
25
44
 
26
45
  ```{note}
package/doc/functions.md CHANGED
@@ -83,19 +83,27 @@ On x86 platforms, only the Cdecl convention can be used for variadic functions.
83
83
 
84
84
  ### Calling conventions
85
85
 
86
+ *Changed in Koffi 2.7*
87
+
86
88
  By default, calling a C function happens synchronously.
87
89
 
88
90
  Most architectures only support one procedure call standard per process. The 32-bit x86 platform is an exception to this, and Koffi supports several x86 conventions:
89
91
 
90
- Convention | Classic form | Prototype form | Description
91
- ------------- | ----------------------------- | -------------- | -------------------------------------------------------------------
92
- **Cdecl** | `koffi.cdecl` or `koffi.func` | _(default)_ | This is the default convention, and the only one on other platforms
93
- **Stdcall** | `koffi.stdcall` | __stdcall | This convention is used extensively within the Win32 API
94
- **Fastcall** | `koffi.fastcall` | __fastcall | Rarely used, uses ECX and EDX for first two parameters
95
- **Thiscall** | `koffi.thiscall` | __thiscall | Rarely used, uses ECX for first parameter
92
+ Convention | Classic form | Prototype form | Description
93
+ ------------- | --------------------------------------------- | -------------- | -------------------------------------------------------------------
94
+ **Cdecl** | `koffi.func(name, ret, params)` | _(default)_ | This is the default convention, and the only one on other platforms
95
+ **Stdcall** | `koffi.func('__stdcall', name, ret, params)` | __stdcall | This convention is used extensively within the Win32 API
96
+ **Fastcall** | `koffi.func('__fastcall', name, ret, params)` | __fastcall | Rarely used, uses ECX and EDX for first two parameters
97
+ **Thiscall** | `koffi.func('__thiscall', name, ret, params)` | __thiscall | Rarely used, uses ECX for first parameter
96
98
 
97
99
  You can safely use these on non-x86 platforms, they are simply ignored.
98
100
 
101
+ ```{note}
102
+ Support for specifying the convention as the first argument of the classic form was introduced in Koffi 2.7.
103
+
104
+ In earlier versions, you had to use `koffi.stdcall()` and similar functions. These functions are still supported but deprecated, and will be removed in Koffi 3.0.
105
+ ```
106
+
99
107
  Below you can find a small example showing how to use a non-default calling convention, with the two syntaxes:
100
108
 
101
109
  ```js
@@ -105,7 +113,7 @@ const koffi = require('koffi');
105
113
  const lib = koffi.load('user32.dll');
106
114
 
107
115
  // The following two declarations are equivalent, and use stdcall on x86 (and the default ABI on other platforms)
108
- const MessageBoxA_1 = lib.stdcall('MessageBoxA', 'int', ['void *', 'str', 'str', 'uint']);
116
+ const MessageBoxA_1 = lib.func('__stdcall', 'MessageBoxA', 'int', ['void *', 'str', 'str', 'uint']);
109
117
  const MessageBoxA_2 = lib.func('int __stdcall MessageBoxA(void *hwnd, str text, str caption, uint type)');
110
118
  ```
111
119
 
package/doc/start.md CHANGED
@@ -99,8 +99,8 @@ const IDYES = 6;
99
99
  const IDNO = 7;
100
100
 
101
101
  // Find functions
102
- const MessageBoxA = lib.stdcall('MessageBoxA', 'int', ['void *', 'str', 'str', 'uint']);
103
- const MessageBoxW = lib.stdcall('MessageBoxW', 'int', ['void *', 'str16', 'str16', 'uint']);
102
+ const MessageBoxA = lib.func('__stdcall', 'MessageBoxA', 'int', ['void *', 'str', 'str', 'uint']);
103
+ const MessageBoxW = lib.func('__stdcall', 'MessageBoxW', 'int', ['void *', 'str16', 'str16', 'uint']);
104
104
 
105
105
  let ret = MessageBoxA(null, 'Do you want another message box?', 'Koffi', MB_YESNO | MB_ICONQUESTION);
106
106
  if (ret == IDYES)
package/index.d.ts CHANGED
@@ -67,18 +67,16 @@ declare module 'koffi' {
67
67
  export interface IKoffiLib {
68
68
  func(definition: string): KoffiFunction;
69
69
  func(name: string, result: TypeSpec, arguments: TypeSpec[]): KoffiFunction;
70
+ func(convention: string, name: string, result: TypeSpec, arguments: TypeSpec[]): KoffiFunction;
70
71
 
71
- cdecl(definition: string): KoffiFunction;
72
- cdecl(name: string, result: TypeSpec, arguments: TypeSpec[]): KoffiFunction;
73
-
74
- stdcall(definition: string): KoffiFunction;
75
- stdcall(name: string, result: TypeSpec, arguments: TypeSpec[]): KoffiFunction;
76
-
77
- fastcall(definition: string): KoffiFunction;
78
- fastcall(name: string, result: TypeSpec, arguments: TypeSpec[]): KoffiFunction;
79
-
80
- thiscall(definition: string): KoffiFunction;
81
- thiscall(name: string, result: TypeSpec, arguments: TypeSpec[]): KoffiFunction;
72
+ /** @deprecated */ cdecl(definition: string): KoffiFunction;
73
+ /** @deprecated */ cdecl(name: string, result: TypeSpec, arguments: TypeSpec[]): KoffiFunction;
74
+ /** @deprecated */ stdcall(definition: string): KoffiFunction;
75
+ /** @deprecated */ stdcall(name: string, result: TypeSpec, arguments: TypeSpec[]): KoffiFunction;
76
+ /** @deprecated */ fastcall(definition: string): KoffiFunction;
77
+ /** @deprecated */ fastcall(name: string, result: TypeSpec, arguments: TypeSpec[]): KoffiFunction;
78
+ /** @deprecated */ thiscall(definition: string): KoffiFunction;
79
+ /** @deprecated */ thiscall(name: string, result: TypeSpec, arguments: TypeSpec[]): KoffiFunction;
82
80
 
83
81
  symbol(name: string, type: TypeSpec): any;
84
82
 
@@ -118,8 +116,10 @@ declare module 'koffi' {
118
116
 
119
117
  export function proto(definition: string): IKoffiCType;
120
118
  export function proto(name: string, result: TypeSpec, arguments: TypeSpec[]): IKoffiCType;
119
+ export function proto(convention: string, name: string, result: TypeSpec, arguments: TypeSpec[]): IKoffiCType;
121
120
  /** @deprecated */ export function callback(definition: string): IKoffiCType;
122
121
  /** @deprecated */ export function callback(name: string, result: TypeSpec, arguments: TypeSpec[]): IKoffiCType;
122
+ /** @deprecated */ export function callback(convention: string, name: string, result: TypeSpec, arguments: TypeSpec[]): IKoffiCType;
123
123
 
124
124
  export function register(callback: Function, type: TypeSpec): IKoffiRegisteredCallback;
125
125
  export function register(thisValue: any, callback: Function, type: TypeSpec): IKoffiRegisteredCallback;
package/index.js CHANGED
@@ -378,8 +378,8 @@ var require_package = __commonJS({
378
378
  "build/dist/src/koffi/package.json"(exports2, module2) {
379
379
  module2.exports = {
380
380
  name: "koffi",
381
- version: "2.6.12",
382
- stable: "2.6.12",
381
+ version: "2.7.0",
382
+ stable: "2.7.0",
383
383
  description: "Fast and simple C FFI (foreign function interface) for Node.js",
384
384
  keywords: [
385
385
  "foreign",
@@ -557,3 +557,12 @@ module.exports = {
557
557
  handle: util.deprecate(native.opaque, "The koffi.handle() function was deprecated in Koffi 2.1, use koffi.opaque() instead", "KOFFI001"),
558
558
  callback: util.deprecate(native.proto, "The koffi.callback() function was deprecated in Koffi 2.4, use koffi.proto() instead", "KOFFI002")
559
559
  };
560
+ var load = module.exports.load;
561
+ module.exports.load = (...args) => {
562
+ let lib = load(...args);
563
+ lib.cdecl = util.deprecate((...args2) => lib.func("__cdecl", ...args2), "The koffi.stdcall() function was deprecated in Koffi 2.7, use koffi.func(...) instead", "KOFFI003");
564
+ lib.stdcall = util.deprecate((...args2) => lib.func("__stdcall", ...args2), 'The koffi.stdcall() function was deprecated in Koffi 2.7, use koffi.func("__stdcall", ...) instead', "KOFFI004");
565
+ lib.fastcall = util.deprecate((...args2) => lib.func("__fastcall", ...args2), 'The koffi.fastcall() function was deprecated in Koffi 2.7, use koffi.func("__fastcall", ...) instead', "KOFFI005");
566
+ lib.thiscall = util.deprecate((...args2) => lib.func("__thiscall", ...args2), 'The koffi.thiscall() function was deprecated in Koffi 2.7, use koffi.func("__thiscall", ...) instead', "KOFFI006");
567
+ return lib;
568
+ };
package/indirect.js CHANGED
@@ -378,8 +378,8 @@ var require_package = __commonJS({
378
378
  "build/dist/src/koffi/package.json"(exports2, module2) {
379
379
  module2.exports = {
380
380
  name: "koffi",
381
- version: "2.6.12",
382
- stable: "2.6.12",
381
+ version: "2.7.0",
382
+ stable: "2.7.0",
383
383
  description: "Fast and simple C FFI (foreign function interface) for Node.js",
384
384
  keywords: [
385
385
  "foreign",
@@ -477,3 +477,12 @@ module.exports = {
477
477
  handle: util.deprecate(native.opaque, "The koffi.handle() function was deprecated in Koffi 2.1, use koffi.opaque() instead", "KOFFI001"),
478
478
  callback: util.deprecate(native.proto, "The koffi.callback() function was deprecated in Koffi 2.4, use koffi.proto() instead", "KOFFI002")
479
479
  };
480
+ var load = module.exports.load;
481
+ module.exports.load = (...args) => {
482
+ let lib = load(...args);
483
+ lib.cdecl = util.deprecate((...args2) => lib.func("__cdecl", ...args2), "The koffi.stdcall() function was deprecated in Koffi 2.7, use koffi.func(...) instead", "KOFFI003");
484
+ lib.stdcall = util.deprecate((...args2) => lib.func("__stdcall", ...args2), 'The koffi.stdcall() function was deprecated in Koffi 2.7, use koffi.func("__stdcall", ...) instead', "KOFFI004");
485
+ lib.fastcall = util.deprecate((...args2) => lib.func("__fastcall", ...args2), 'The koffi.fastcall() function was deprecated in Koffi 2.7, use koffi.func("__fastcall", ...) instead', "KOFFI005");
486
+ lib.thiscall = util.deprecate((...args2) => lib.func("__thiscall", ...args2), 'The koffi.thiscall() function was deprecated in Koffi 2.7, use koffi.func("__thiscall", ...) instead', "KOFFI006");
487
+ return lib;
488
+ };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koffi",
3
- "version": "2.6.12",
4
- "stable": "2.6.12",
3
+ "version": "2.7.0",
4
+ "stable": "2.7.0",
5
5
  "description": "Fast and simple C FFI (foreign function interface) for Node.js",
6
6
  "keywords": [
7
7
  "foreign",
@@ -5599,7 +5599,6 @@ public:
5599
5599
  AsyncPool(int threads, bool leak);
5600
5600
 
5601
5601
  int GetWorkerCount() const { return (int)workers.len; }
5602
- int CountPendingTasks() const { return pending_tasks; }
5603
5602
 
5604
5603
  void RegisterAsync();
5605
5604
  void UnregisterAsync();
@@ -5673,11 +5672,6 @@ bool Async::Sync()
5673
5672
  return success;
5674
5673
  }
5675
5674
 
5676
- int Async::CountPendingTasks()
5677
- {
5678
- return pool->CountPendingTasks();
5679
- }
5680
-
5681
5675
  bool Async::IsTaskRunning()
5682
5676
  {
5683
5677
  return async_running_task;
@@ -5806,6 +5800,11 @@ void AsyncPool::AddTask(Async *async, const std::function<bool()> &func)
5806
5800
  pending_cv.notify_all();
5807
5801
  sync_cv.notify_all();
5808
5802
  }
5803
+
5804
+ // Limit queue size (back pressure)
5805
+ while (pending_tasks >= RG_ASYNC_MAX_PENDING_TASKS) {
5806
+ RunTasks(0);
5807
+ }
5809
5808
  }
5810
5809
 
5811
5810
  void AsyncPool::RunWorker(int worker_idx)
@@ -93,6 +93,8 @@ namespace RG {
93
93
 
94
94
  #define RG_ASYNC_MAX_THREADS 2048
95
95
  #define RG_ASYNC_MAX_IDLE_TIME 10000
96
+ #define RG_ASYNC_MAX_PENDING_TASKS 1024
97
+
96
98
  #define RG_FIBER_DEFAULT_STACK_SIZE Kibibytes(128)
97
99
 
98
100
  // ------------------------------------------------------------------------
@@ -4265,8 +4267,6 @@ public:
4265
4267
  void Run(const std::function<bool()> &f);
4266
4268
  bool Sync();
4267
4269
 
4268
- int CountPendingTasks();
4269
-
4270
4270
  static bool IsTaskRunning();
4271
4271
  static int GetWorkerIdx();
4272
4272
  static int GetWorkerCount();
@@ -880,35 +880,50 @@ static Napi::Value CreateArrayType(const Napi::CallbackInfo &info)
880
880
  return WrapType(env, instance, type);
881
881
  }
882
882
 
883
- static bool ParseClassicFunction(Napi::Env env, Napi::String name, Napi::Value ret,
884
- Napi::Array parameters, FunctionInfo *func)
883
+ static bool ParseClassicFunction(const Napi::CallbackInfo &info, FunctionInfo *out_func)
885
884
  {
885
+ Napi::Env env = info.Env();
886
886
  InstanceData *instance = env.GetInstanceData<InstanceData>();
887
887
 
888
+ Napi::String name = info[0u].As<Napi::String>();
889
+ Napi::Value ret = info[1u];
890
+ Napi::Array parameters = info[2u].As<Napi::Array>();
891
+
892
+ // Detect optional call convention
893
+ if (name.IsString() && DetectCallConvention(name.Utf8Value().c_str(), &out_func->convention)) {
894
+ if (info.Length() < 4) {
895
+ ThrowError<Napi::TypeError>(env, "Expected 4 arguments, got %1", info.Length());
896
+ return false;
897
+ }
898
+
899
+ name = info[1u].As<Napi::String>();
900
+ ret = info[2u];
901
+ parameters = info[3u].As<Napi::Array>();
902
+ }
903
+
888
904
  #ifdef _WIN32
889
- if (!name.IsString() && !name.IsNumber()) {
890
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value for name, expected string or integer", GetValueType(instance, name));
891
- return false;
905
+ if (name.IsNumber()) {
906
+ out_func->ordinal_name = name.As<Napi::Number>().Int32Value();
907
+ name = name.ToString();
892
908
  }
893
- #else
909
+ #endif
894
910
  if (!name.IsString()) {
895
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value for name, expected string", GetValueType(instance, name));
911
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value for name, expected string or integer", GetValueType(instance, name));
896
912
  return false;
897
913
  }
898
- #endif
899
914
 
900
- func->name = DuplicateString(name.ToString().Utf8Value().c_str(), &instance->str_alloc).ptr;
915
+ out_func->name = DuplicateString(name.ToString().Utf8Value().c_str(), &instance->str_alloc).ptr;
901
916
 
902
- func->ret.type = ResolveType(ret);
903
- if (!func->ret.type)
917
+ out_func->ret.type = ResolveType(ret);
918
+ if (!out_func->ret.type)
904
919
  return false;
905
- if (!CanReturnType(func->ret.type)) {
906
- ThrowError<Napi::TypeError>(env, "You are not allowed to directly return %1 values (maybe try %1 *)", func->ret.type->name);
920
+ if (!CanReturnType(out_func->ret.type)) {
921
+ ThrowError<Napi::TypeError>(env, "You are not allowed to directly return %1 values (maybe try %1 *)", out_func->ret.type->name);
907
922
  return false;
908
923
  }
909
924
 
910
925
  if (!parameters.IsArray()) {
911
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value for parameters of '%2', expected an array", GetValueType(instance, parameters), func->name);
926
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value for parameters of '%2', expected an array", GetValueType(instance, parameters), out_func->name);
912
927
  return false;
913
928
  }
914
929
 
@@ -918,7 +933,7 @@ static bool ParseClassicFunction(Napi::Env env, Napi::String name, Napi::Value r
918
933
  Napi::String str = parameters.Get(parameters_len - 1).As<Napi::String>();
919
934
 
920
935
  if (str.IsString() && str.Utf8Value() == "...") {
921
- func->variadic = true;
936
+ out_func->variadic = true;
922
937
  parameters_len--;
923
938
  }
924
939
  }
@@ -934,21 +949,21 @@ static bool ParseClassicFunction(Napi::Env env, Napi::String name, Napi::Value r
934
949
  ThrowError<Napi::TypeError>(env, "Type %1 cannot be used as a parameter", param.type->name);
935
950
  return false;
936
951
  }
937
- if (func->parameters.len >= MaxParameters) {
952
+ if (out_func->parameters.len >= MaxParameters) {
938
953
  ThrowError<Napi::TypeError>(env, "Functions cannot have more than %1 parameters", MaxParameters);
939
954
  return false;
940
955
  }
941
- if ((param.directions & 2) && ++func->out_parameters >= MaxParameters) {
956
+ if ((param.directions & 2) && ++out_func->out_parameters >= MaxParameters) {
942
957
  ThrowError<Napi::TypeError>(env, "Functions cannot have more than %1 output parameters", MaxParameters);
943
958
  return false;
944
959
  }
945
960
 
946
961
  param.offset = (int8_t)j;
947
962
 
948
- func->parameters.Append(param);
963
+ out_func->parameters.Append(param);
949
964
  }
950
965
 
951
- func->required_parameters = (int8_t)func->parameters.len;
966
+ out_func->required_parameters = (int8_t)out_func->parameters.len;
952
967
 
953
968
  return true;
954
969
  }
@@ -962,7 +977,7 @@ static Napi::Value CreateFunctionType(const Napi::CallbackInfo &info)
962
977
  RG_DEFER_N(err_guard) { instance->callbacks.RemoveLast(1); };
963
978
 
964
979
  if (info.Length() >= 3) {
965
- if (!ParseClassicFunction(env, info[0u].As<Napi::String>(), info[1u], info[2u].As<Napi::Array>(), func))
980
+ if (!ParseClassicFunction(info, func))
966
981
  return env.Null();
967
982
  } else if (info.Length() >= 1) {
968
983
  if (!info[0].IsString()) {
@@ -1519,7 +1534,7 @@ extern "C" void RelayCallback(Size idx, uint8_t *own_sp, uint8_t *caller_sp, Bac
1519
1534
  }
1520
1535
  }
1521
1536
 
1522
- static Napi::Value FindLibraryFunction(const Napi::CallbackInfo &info, CallConvention convention)
1537
+ static Napi::Value FindLibraryFunction(const Napi::CallbackInfo &info)
1523
1538
  {
1524
1539
  Napi::Env env = info.Env();
1525
1540
  InstanceData *instance = env.GetInstanceData<InstanceData>();
@@ -1529,10 +1544,9 @@ static Napi::Value FindLibraryFunction(const Napi::CallbackInfo &info, CallConve
1529
1544
  RG_DEFER { func->Unref(); };
1530
1545
 
1531
1546
  func->lib = lib->Ref();
1532
- func->convention = convention;
1533
1547
 
1534
1548
  if (info.Length() >= 3) {
1535
- if (!ParseClassicFunction(env, info[0u].As<Napi::String>(), info[1u], info[2u].As<Napi::Array>(), func))
1549
+ if (!ParseClassicFunction(info, func))
1536
1550
  return env.Null();
1537
1551
  } else if (info.Length() >= 1) {
1538
1552
  if (!info[0].IsString()) {
@@ -1562,7 +1576,7 @@ static Napi::Value FindLibraryFunction(const Napi::CallbackInfo &info, CallConve
1562
1576
  }
1563
1577
 
1564
1578
  #ifdef _WIN32
1565
- if (info[0].IsString()) {
1579
+ if (func->ordinal_name < 0) {
1566
1580
  if (func->decorated_name) {
1567
1581
  func->native = (void *)GetProcAddress((HMODULE)lib->module, func->decorated_name);
1568
1582
  }
@@ -1570,7 +1584,7 @@ static Napi::Value FindLibraryFunction(const Napi::CallbackInfo &info, CallConve
1570
1584
  func->native = (void *)GetProcAddress((HMODULE)lib->module, func->name);
1571
1585
  }
1572
1586
  } else {
1573
- uint16_t ordinal = (uint16_t)info[0].As<Napi::Number>().Uint32Value();
1587
+ uint16_t ordinal = (uint16_t)func->ordinal_name;
1574
1588
 
1575
1589
  func->decorated_name = nullptr;
1576
1590
  func->native = (void *)GetProcAddress((HMODULE)lib->module, (LPCSTR)(size_t)ordinal);
@@ -1720,20 +1734,13 @@ static Napi::Value LoadSharedLibrary(const Napi::CallbackInfo &info)
1720
1734
  func.AddFinalizer([](Napi::Env, LibraryHolder *lib) { lib->Unref(); }, lib); \
1721
1735
  obj.Set((Name), func); \
1722
1736
  } while (false)
1723
- #define ADD_CONVENTION(Name, Value) ADD_METHOD((Name), FindLibraryFunction(info, Value))
1724
-
1725
- ADD_CONVENTION("func", CallConvention::Cdecl);
1726
- ADD_CONVENTION("cdecl", CallConvention::Cdecl);
1727
- ADD_CONVENTION("stdcall", CallConvention::Stdcall);
1728
- ADD_CONVENTION("fastcall", CallConvention::Fastcall);
1729
- ADD_CONVENTION("thiscall", CallConvention::Thiscall);
1730
1737
 
1738
+ ADD_METHOD("func", FindLibraryFunction(info));
1731
1739
  ADD_METHOD("symbol", FindSymbol(info));
1732
1740
 
1733
1741
  // We can't unref the library after unload, obviously
1734
1742
  obj.Set("unload", Napi::Function::New(env, UnloadLibrary, "unload", (void *)lib->Ref()));
1735
1743
 
1736
- #undef ADD_CONVENTION
1737
1744
  #undef ADD_METHOD
1738
1745
 
1739
1746
  return obj;
@@ -2326,7 +2333,6 @@ static Napi::Object InitModule(Napi::Env env, Napi::Object exports)
2326
2333
  Napi::Object types = InitBaseTypes(env);
2327
2334
  exports.Set("types", types);
2328
2335
 
2329
- exports.Set("internal", Napi::Boolean::New(env, false));
2330
2336
  exports.Set("version", Napi::String::New(env, RG_STRINGIFY(VERSION)));
2331
2337
 
2332
2338
  return exports;
@@ -220,6 +220,9 @@ struct FunctionInfo {
220
220
 
221
221
  const char *name;
222
222
  const char *decorated_name; // Only set for some platforms/calling conventions
223
+ #ifdef _WIN32
224
+ int ordinal_name = -1;
225
+ #endif
223
226
  const LibraryHolder *lib = nullptr;
224
227
 
225
228
  void *native;
@@ -40,15 +40,7 @@ bool PrototypeParser::Parse(const char *str, FunctionInfo *out_func)
40
40
  MarkError("You are not allowed to directly return %1 values (maybe try %1 *)", out_func->ret.type->name);
41
41
  return false;
42
42
  }
43
- if (Match("__cdecl")) {
44
- out_func->convention = CallConvention::Cdecl;
45
- } else if (Match("__stdcall")) {
46
- out_func->convention = CallConvention::Stdcall;
47
- } else if (Match("__fastcall")) {
48
- out_func->convention = CallConvention::Fastcall;
49
- } else if (Match("__thiscall")) {
50
- out_func->convention = CallConvention::Thiscall;
51
- }
43
+ offset += (offset < tokens.len && DetectCallConvention(tokens[offset], &out_func->convention));
52
44
  out_func->name = ParseIdentifier();
53
45
 
54
46
  Consume("(");
@@ -1508,6 +1508,25 @@ Napi::Function WrapFunction(Napi::Env env, const FunctionInfo *func)
1508
1508
  return wrapper;
1509
1509
  }
1510
1510
 
1511
+ bool DetectCallConvention(Span<const char> name, CallConvention *out_convention)
1512
+ {
1513
+ if (name == "__cdecl") {
1514
+ *out_convention = CallConvention::Cdecl;
1515
+ return true;
1516
+ } else if (name == "__stdcall") {
1517
+ *out_convention = CallConvention::Stdcall;
1518
+ return true;
1519
+ } else if (name == "__fastcall") {
1520
+ *out_convention = CallConvention::Fastcall;
1521
+ return true;
1522
+ } else if (name == "__thiscall") {
1523
+ *out_convention = CallConvention::Thiscall;
1524
+ return true;
1525
+ } else {
1526
+ return false;
1527
+ }
1528
+ }
1529
+
1511
1530
  static int AnalyseFlatRec(const TypeInfo *type, int offset, int count, FunctionRef<void(const TypeInfo *type, int offset, int count)> func)
1512
1531
  {
1513
1532
  if (type->primitive == PrimitiveKind::Record) {
@@ -208,6 +208,8 @@ static inline Napi::Array GetOwnPropertyNames(Napi::Object obj)
208
208
 
209
209
  Napi::Function WrapFunction(Napi::Env env, const FunctionInfo *func);
210
210
 
211
+ bool DetectCallConvention(Span<const char> name, CallConvention *out_convention);
212
+
211
213
  int AnalyseFlat(const TypeInfo *type, FunctionRef<void(const TypeInfo *type, int offset, int count)> func);
212
214
 
213
215
  void DumpMemory(const char *type, Span<const uint8_t> bytes);