A colleague of mine needed help wrapping some C DLLs for NodeJS. He’s using the Node FFI API for the wrapping, which unfortunately is a little light on documentation. The problem was that by default Node FFI wraps cdecl functions and there is no mention of stdcall anywhere. In fact the consensus on the net seems to be that it’s not possible at all. Reading the sources proved more fruitful and so I document the way here for future generations to find:
The standard way of initializing a FFI wrapper using the array in the constructor
var libm = ffi.Library('libm', {
actually takes an additional parameter with the calling convention, but in stdcall the function names are often decorated with an additional “@x” which denotes the bytes the function parameters need on the stack. Problem is, blah@x is not a valid identifier and in the array the Javascript function pointer always has the same name as the function in the DLL. The solution is to manually wrap the functions, which I actually prefer anyway as the function pointer doesn’t end in a struct but can be used directly afterwards:
'ceil': [ 'double', [ 'double' ] ]
});
var TcAdsdll = new ffi.DynamicLibrary('TcAdsDll', ffi.RTLD_NOW)
var AdsPortOpen = ffi.ForeignFunction(TcAdsdll.get('_AdsPortOpen@0'), 'long', [], ffi.FFI_STDCALL)
The resulting wrapper is called using “AdsPortOpen()” and it accesses the function with the decorated name “_AdsPortOpen@0”. The easiest way to get the decorated name is using the dumpbin utility from Visual Studio with the “/exports” parameter:
C:\Windows\System32>dumpbin /exports gdi32.dll Microsoft (R) COFF/PE Dumper Version 10.00.40219.01 Copyright (C) Microsoft Corporation. All rights reserved. Dump of file gdi32.dll File Type: DLL Section contains the following exports for GDI32.dll 00000000 characteristics 573C8294 time date stamp Wed May 18 16:56:20 2016 0.00 version 1000 ordinal base 727 number of functions 715 number of names ordinal hint RVA name 1012 0 00043F40 AbortDoc = _AbortDoc@4 1013 1 00045806 AbortPath = _AbortPath@4 1014 2 0003BA5C AddFontMemResourceEx = _AddFontMemResourceEx@16 [...]
does this still work for you because ffi.FFI_STDCALL doesn’t exist for me on lastest version.
It’s still part of the Node FFI source, in fact nothing has changed since then, so I guess it should still work…
hmm… with const ffi = require(‘ffi’); (version 2.2.0). ffi.FFI_STDCALL is not defined for me. :/
It’s only defined in the 32-bit Windows version, because that’s the only version where it makes sense. Might that be the problem?
ahh, that will likely be the reason then. Thank you.
you saved my life !
Cool, Iām glad that you were able to find the answer here š