NodeRT is a tool that automatically generates node.js Native add-on wrappers for WinRT APIs.
NodeRT automatically exposes Microsoft’s WinRT APIs to the node.js environment by generating node modules. This enables node.js developers to write code that consumes native Windows capabilities. The generated modules' APIs are (almost) the same as the WinRT APIs listed in MSDN. NodeRT can be used to generate node.js modules both from command line (NodeRTCmd) and from its UI tool (NodeRTUI).
NodeRT is developed and released by a group of node.js enthusiasts at Microsoft.
Here is an example of using NodeRT windows.devices.geolocation module to retrieve the current location:
var geolocation = require('windows.devices.geolocation');
var locator = new geolocation.Geolocator();
locator.getGeopositionAsync( function(err, res) {
if (err) {
console.error(err);
return;
}
console.info('(', res.coordinate.longitude, ',', res.coordinate.latitude, ')');
});
For more examples of what NodeRT can do, check out our samples section.
Generating a NodeRT module using the UI
Generating a NodeRT module using the cmd line interface
Consuming a NodeRT module in node.js
First, in order to use WinRT you must be running on a Windows environment that supports WinRT- meaning Windows 8.1, Windows 8, or Windows Server 2012.
In order to use NodeRT, make sure you have the following installed:
- Visual Studio 2013, or VS 2013 Express for Windows Desktop, for generating Windows 8.1 compatible modules, or Visual Studio 2012 for generating Windows 8 compatible modules.
- node.js (version > 10.*) - from www.nodejs.org
- node.js native development files - these files can be installed using the following cmd-line:
node-gyp install
(In order to make sure those files are installed - check if the following directory exists:
c:\users\[your user name]\.node_gyp\[your node.js version]
Another option is to download the node.js source code to your machine and build it. More information on this is available in the node.js site/github repository.
Next, download the NodeRT binaries from here, or clone this repository to your machine and build the NodeRT solution using Visual Studio.
First, launch the UI tool by running NodeRTUI.exe:
Then, follow this short list of steps in order to create a NodeRT module:
- Choose a WinMD file:
- For Windows 8.1 SDK:
c:\Program Files (x86)\Windows Kits\8.1\References\CommonConfiguration\Neutral\Windows.winmd
- For Windows 8.0 SDK:
c:\Program Files (x86)\Windows Kits\8.0\References\CommonConfiguration\Neutral\Windows.winmd
- For Windows 8.1 SDK:
- Choose a namespace to generate from the list of namespaces.
- Select whether you are generating a Windows 8.1 compatible module, using VS2013 or a Windows 8.0 compatible module using VS2012.
- Choose the node.js development files root, where the node header files & libs reside. For node.js, you'll probably want the location that gyp uses to compile the native addons. Note that the default value will be c:\users\[current user]\.node-gyp\[latest version]. If you choose other directories, just make sure they have the same directory structures as the .node-gyp folder.
- Choose code generation & output directories, or just stick with the default ones.
- You're good to go, hit the Generate & Build button! A message box with (hopefully) a success message should appear shortly.
NodeRT modules generation is available via a cmd-line interface using the NodeRTCmd tool.
An example of generating the Windows.Devices.Geolocation namespace from the Windows 8.1 Windows.winmd:
NodeRTCmd.exe --winmd "c:\Program Files (x86)\Windows Kits\8.1\References\CommonConfiguration\Neutral\Windows.winmd" --codegendir c:\NodeRT\codegen --outdir c:\NodeRT\output --namespace Windows.Devices.Geolocation
Note that omitting the --namespace option will generate all of the namespaces in the Winmd file.
The following is the list of options that the tool supports:
--winmd [path] File path to winmd file from which the module
will be generated
--namespaces Lists all of the namespaces in the winmd file
(only needs --winmd)
--namespace [namespace] The namespace to generate from the winmd when
not specified , all namespaces will be generated
--codegendir [path] The directory in which the project source code
will be generated
--outdir [path] The output dir in which the compiled NodeRT module
will be created in
--nodesrcdir [path] Optional, path to the node src/lib files root
--vs [Vs2012|Vs2013] Optional, VS version to use, default is Vs2013
--help Print this help screen
Requiring a generated NodeRT module is just like requiring any other node.js module - if for example, you've just generated Windows.Devices.Geolocation, copy the generated windows.devices.geolocation directory from the output folder to a node_modules folder near you (or use a full path), and run:
var geolocation = require('windows.devices.geolocation');
If you are working in the node console (AKA REPL), then entering geolocation will result in printing the contents of the namespace:
Creating a new WinRT object is done with the new operator. In order to inspect the method and properties of the object, you can print its prototype: For example, creating a new Geolocator object in REPL:
var locator = new geolocation.Geolocator();
//print the prototype
locator.__proto__
And the output will be:
(Note that property values are fetched on the fly, and hence have undefined values when printing the prototype)
Classes and fields naming
We use the same convention used for WinRT javascript applications:
-
Class/Enum names have the first letter in upper-case
-
Class/Enum fields, that is properties, methods, and events, both member and static have the first letter in lower-case, the rest of the name is according to MSDN.
-
Enums are just javascript objects with keys corresponding to the enum fields and values to the enum fields numeric values.
Properties
Using Properties of an object is just straight-forward javascript, for example:
locator.reportInterval = 2000;
console.info(locator.reportInterval);
Synchronous methods
Again, straight-forward javascript, just make the call with the appropriate arguments. If there are several WinRT overloads for the method, make the call with the right set of arguments and the correct overload of the method will be called:
var xml = require('windows.data.xml.dom');
var xmlDoc = new xml.XmlDocument();
toastXml.loadXml('<node>some text here</node>');
Asynchronous methods
Each async method accepts the same variables as are listed in the MSDN, with the addition of a completion callback as the last argument.
This callback will be called when the function has finished, and will receive an error as the first argument, and the result as the second argument:
locator.getGeopositionAsync( function(err, res) {
// result is of type geoposition
if (err) {
console.error(err);
return;
}
console.info('(',res.coordinate.longitude, res.coordinate.latitude, ')');
});
If you wish to use the exact method signatures that are listed in the MSDN examples, you can use the nodert-promisize module (located in modules/nodert-promisize), or any other similar node.js library:
var promisize = require('nodert-promisize').promisize;
var geolocation = promisize('windows.devices.geolocation');
var locator = new geolocation.Geolocator();
locator.getPositionAsync(filePath)
.then(function(res) {
console.info('(',res.coordinate.longitude, res.coordinate.latitude, ')');
},
function(err) {
console.error(err);
}
);
Events
Registering to events is done using the class' on method (which is equivalent to addListener), which receives the event name (case insensitive) and the event handler function. For example:
var handler = function handler(sender, eventArgs) {
console.info('status is:', eventArgs.status);
};
locator.on('statusChanged', handler);
Unregistering from an event is done the same way, using the class's off or removeListener methods. Just make sure to store the event handler in order to be able to use it.
// using same event handler as in the example above
locator.off('statusChanged', handler);
Separation into namespaces and cross namespace usage
Each NodeRT module represents a single namespace.
For instance, windows.storage will have a NodeRT module, and windows.storage.streams will have another NodeRT module.
The reason for this separation is strictly due to performance considerations.
(We didn't want to have a huge NodeRT module that will cause the memory of node.js to blow up while most of the namespaces probably won't be used in each script).
This architecture means that in case you are using a NodeRT module which contains a function, property, or event which returns an object from another namespace, then you will need to require that namespace before calling that function/property/event.
For example:
var capture = require('windows.media.capture');
// we also require this module in order to be able to access device controller properties
var devices = require('windows.media.devices');
var capture = new capture.MediaCapture();
capture.initializeAsync(function (err, res) {
if (err) {
return console.info(err);
}
// get the device controller, its type (VideoDeviceController) is defined in the
// windows.media.devices namespace - so, we had to require that namespace as well
var deviceController = capture.videoDeviceController;
// we can now use the VideoDeviceController regularly
deviceController.brightness.trySetValue(-1);
});
Using WinRT streams in node.js
In order to support the use of WinRT streams in node.js, we have created the nodert-streams module, which bridges between WinRT streams and node.js streams.
This bridge enable the conversion of WinRT streams to node.js streams, such that WinRT streams could be used just as regular node.js streams.
NodeRT is released under the Apache 2.0 license. For more information, please take a look at the license file.
In order to build NodeRT we used these 2 great libraries: * RazorTemplates - https://github.com/volkovku/RazorTemplates * RX.NET - https://github.com/Reactive-Extensions/Rx.NET/
You are welcome to send us any bugs you may find, suggestions, or any other comments. Before sending anything, please go over the repository issues list, just to make sure that it isn't already there.
You are more than welcome to fork this repository and send us a pull request if you feel that what you've done should be included.