Wrapping stdcall functions in Node FFI

By | 2016-11-29

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', {
'ceil': [ 'double', [ 'double' ] ]
});
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:
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
[...]

7 thoughts on “Wrapping stdcall functions in Node FFI

  1. Meirion

    does this still work for you because ffi.FFI_STDCALL doesn’t exist for me on lastest version.

    Reply
    1. Marcel Post author

      It’s still part of the Node FFI source, in fact nothing has changed since then, so I guess it should still work…

      Reply
      1. Meirion

        hmm… with const ffi = require(‘ffi’); (version 2.2.0). ffi.FFI_STDCALL is not defined for me. :/

        Reply
        1. Marcel Post author

          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?

          Reply
          1. Meirion

            ahh, that will likely be the reason then. Thank you.

    1. Marcel Post author

      Cool, Iā€˜m glad that you were able to find the answer here šŸ™‚

      Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.