Working with Windows native code from node.js

[UPDATE 02 Feb 2016: While this post discusses Win32 access, here’s an interesting option for UWP access from JXCore that should eventually work with nodejs when the Microsoft PR for Chakra is merged.]

While the node.js ecosystem provides an amazing number of modules covering almost every imaginable use, sometimes you want to work with existing code created in other languages and tool chains. For example, you may have an existing C++ library or perhaps you want to call operating systems APIs not yet available in npm or elsewhere.

When integrating between different language infrastructures you have a choice of which side of the divide to write the required glue code. Glue that provides data marshalling, function calling and event processing. If you want to access code with a C style calling convention then it relatively easy to add code on the C side as node is itself created in C++. This is easily enough done by  creating C/C++ addons but often involves reams of boilerplate code. However, if you do choose that option then you’re going to want to use a tool like nan to make your life tolerable. As the nan readme explains:

Thanks to the crazy changes in V8 (and some in Node core), keeping native addons compiling happily across versions, particularly 0.10 to 0.12 to 4.0, is a minor nightmare. The goal of this project is to store all logic necessary to develop native Node.js add-ons without having to inspect NODE_MODULE_VERSION and get yourself into a macro-tangle.

If you want to work on the Javascript side of the divide then ref by provides all the facilities you need for marshalling to/from the C world. It does this by extending node’s Buffer class to provide a type system and facilities for:

  • Getting the memory address of a Buffer
  • Checking the endianness of the processor
  • Checking if a Buffer represents the NULL pointer
  • Reading and writing “pointers” with Buffers
  • Reading and writing C Strings (NULL-terminated)
  • Reading and writing JavaScript Object references
  • Reading and writing int64_t and uint64_t values
  • A “type” convention to define the contents of a Buffer

Further related  ref modules support javascript representations of other C/C++ types including arrays, structures and unions.

Building on ref’s facilities is node-fii which provides a foreign function interface (ffi) for loading and calling functions exported by dynamic libraries (dlls on Windows). It is also possible to call functions in the current process, ideal for functions in static libraries.

While this eliminates large amounts of C boilerplate, it does have a significant calling overhead. Accordingly you are unlikely to want to use it for functions called in a tight loop or otherwise time sensitive applications.

Here’s a simple example from the lib-ffi documentation for wrapping libm’s ceil() function which takes a double parameter and returns a double result and also the static atoi() which takes a string and returns an int.

A more complex example can be seen is some code I wrote for the GPII system for automatic personalisation from preferences. This is perhaps a slightly unusual application of Node.js as it runs on a Windows device in order to launch and configure various Windows’ settings and assistive technology programmes.

The actual code provides a function GetDisplayResolution() that calls the Windows API EnumDisplaySettings() which returns into the fairly complex DEVICEMODE structure. Note that the DEVMODE structure includes nested unions of structures and while the ref modules support these I decided to  flattened out the declaration (after testing my assumptions about packing and padding).

This entry was posted in development and tagged , . Bookmark the permalink.
Skip to top

Comments

4 Responses to Working with Windows native code from node.js

  1. prabhat singh says:

    Hi,

    Nice article. I wanted to try getting current caret position, so came to your blog. I tried the following, but it doen’t work.

    var ffi = require(‘ffi’);
    var ref = require(‘ref’);

    var voidPtr = ref.refType(ref.types.void);
    var user32 = ffi.Library(‘user32.dll’, {
    GetCaretPos:[‘bool’,[voidPtr]]
    });
    var pbuf = new Buffer(2);
    caretpos = user32.GetCaretPos(pbuf);
    var cpos =(new Uint8Array(pbuf));
    console.log(“>”,cpos ); //Doesn’t work **> Uint8Array [ 0, 0, 0, 0 ]**

    Reply
  2. Fabrício Lélis says:

    Hi,
    Great article. I tried your example to GetDisplayResolution but, this error occurred:
    if (c.FALSE !== windows.EnumDisplaySettingsW(ref.NULL, c.ENUM_CURRENT_SETTINGS, dm.ref()))
    ^

    ReferenceError: c is not defined
    at Object.windows.getScreenResolution
    at Function.Module.runMain (module.js:605:10)
    at startup (bootstrap_node.js:158:16)
    at bootstrap_node.js:575:3

    Where is c defined? Can you help me?
    Thanks in advance.

    Reply

Leave a Reply