722 lines
24 KiB
HTML
722 lines
24 KiB
HTML
<!doctype html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<title>Addons Node.js v0.8.14 Manual & Documentation</title>
|
|
<link rel="stylesheet" href="assets/style.css">
|
|
<link rel="stylesheet" href="assets/sh.css">
|
|
<link rel="canonical" href="http://nodejs.org/api/addons.html">
|
|
</head>
|
|
<body class="alt apidoc" id="api-section-addons">
|
|
<div id="intro" class="interior">
|
|
<a href="/" title="Go back to the home page">
|
|
<img id="logo" src="http://nodejs.org/images/logo-light.png" alt="node.js">
|
|
</a>
|
|
</div>
|
|
<div id="content" class="clearfix">
|
|
<div id="column2" class="interior">
|
|
<ul>
|
|
<li><a href="/" class="home">Home</a></li>
|
|
<li><a href="/download/" class="download">Download</a></li>
|
|
<li><a href="/about/" class="about">About</a></li>
|
|
<li><a href="http://search.npmjs.org/" class="npm">npm Registry</a></li>
|
|
<li><a href="http://nodejs.org/api/" class="docs current">Docs</a></li>
|
|
<li><a href="http://blog.nodejs.org" class="blog">Blog</a></li>
|
|
<li><a href="/community/" class="community">Community</a></li>
|
|
<li><a href="/logos/" class="logos">Logos</a></li>
|
|
<li><a href="http://jobs.nodejs.org/" class="jobs">Jobs</a></li>
|
|
</ul>
|
|
<p class="twitter"><a href="http://twitter.com/nodejs">@nodejs</a></p>
|
|
</div>
|
|
|
|
<div id="column1" class="interior">
|
|
<header>
|
|
<h1>Node.js v0.8.14 Manual & Documentation</h1>
|
|
<div id="gtoc">
|
|
<p>
|
|
<a href="index.html" name="toc">Index</a> |
|
|
<a href="all.html">View on single page</a> |
|
|
<a href="addons.json">View as JSON</a>
|
|
</p>
|
|
</div>
|
|
<hr>
|
|
</header>
|
|
|
|
<div id="toc">
|
|
<h2>Table of Contents</h2>
|
|
<ul>
|
|
<li><a href="#addons_addons">Addons</a><ul>
|
|
<li><a href="#addons_hello_world">Hello world</a></li>
|
|
<li><a href="#addons_addon_patterns">Addon patterns</a><ul>
|
|
<li><a href="#addons_function_arguments">Function arguments</a></li>
|
|
<li><a href="#addons_callbacks">Callbacks</a></li>
|
|
<li><a href="#addons_object_factory">Object factory</a></li>
|
|
<li><a href="#addons_function_factory">Function factory</a></li>
|
|
<li><a href="#addons_wrapping_c_objects">Wrapping C++ objects</a></li>
|
|
<li><a href="#addons_factory_of_wrapped_objects">Factory of wrapped objects</a></li>
|
|
<li><a href="#addons_passing_wrapped_objects_around">Passing wrapped objects around</a></li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
|
|
</div>
|
|
|
|
<div id="apicontent">
|
|
<h1>Addons<span><a class="mark" href="#addons_addons" id="addons_addons">#</a></span></h1>
|
|
<p>Addons are dynamically linked shared objects. They can provide glue to C and
|
|
C++ libraries. The API (at the moment) is rather complex, involving
|
|
knowledge of several libraries:
|
|
|
|
</p>
|
|
<ul>
|
|
<li><p>V8 JavaScript, a C++ library. Used for interfacing with JavaScript:
|
|
creating objects, calling functions, etc. Documented mostly in the
|
|
<code>v8.h</code> header file (<code>deps/v8/include/v8.h</code> in the Node source tree),
|
|
which is also available <a href="http://izs.me/v8-docs/main.html">online</a>.</p>
|
|
</li>
|
|
<li><p><a href="https://github.com/joyent/libuv">libuv</a>, C event loop library. Anytime one
|
|
needs to wait for a file descriptor to become readable, wait for a timer, or
|
|
wait for a signal to received one will need to interface with libuv. That is,
|
|
if you perform any I/O, libuv will need to be used.</p>
|
|
</li>
|
|
<li><p>Internal Node libraries. Most importantly is the <code>node::ObjectWrap</code>
|
|
class which you will likely want to derive from.</p>
|
|
</li>
|
|
<li><p>Others. Look in <code>deps/</code> for what else is available.</p>
|
|
</li>
|
|
</ul>
|
|
<p>Node statically compiles all its dependencies into the executable. When
|
|
compiling your module, you don't need to worry about linking to any of these
|
|
libraries.
|
|
|
|
|
|
</p>
|
|
<h2>Hello world<span><a class="mark" href="#addons_hello_world" id="addons_hello_world">#</a></span></h2>
|
|
<p>To get started let's make a small Addon which is the C++ equivalent of
|
|
the following JavaScript code:
|
|
|
|
</p>
|
|
<pre><code>exports.hello = function() { return 'world'; };</code></pre>
|
|
<p>First we create a file <code>hello.cc</code>:
|
|
|
|
</p>
|
|
<pre><code>#include <node.h>
|
|
#include <v8.h>
|
|
|
|
using namespace v8;
|
|
|
|
Handle<Value> Method(const Arguments& args) {
|
|
HandleScope scope;
|
|
return scope.Close(String::New("world"));
|
|
}
|
|
|
|
void init(Handle<Object> target) {
|
|
target->Set(String::NewSymbol("hello"),
|
|
FunctionTemplate::New(Method)->GetFunction());
|
|
}
|
|
NODE_MODULE(hello, init)</code></pre>
|
|
<p>Note that all Node addons must export an initialization function:
|
|
|
|
</p>
|
|
<pre><code>void Initialize (Handle<Object> target);
|
|
NODE_MODULE(module_name, Initialize)</code></pre>
|
|
<p>There is no semi-colon after <code>NODE_MODULE</code> as it's not a function (see <code>node.h</code>).
|
|
|
|
</p>
|
|
<p>The <code>module_name</code> needs to match the filename of the final binary (minus the
|
|
.node suffix).
|
|
|
|
</p>
|
|
<p>The source code needs to be built into <code>hello.node</code>, the binary Addon. To
|
|
do this we create a file called <code>binding.gyp</code> which describes the configuration
|
|
to build your module in a JSON-like format. This file gets compiled by
|
|
<a href="https://github.com/TooTallNate/node-gyp">node-gyp</a>.
|
|
|
|
</p>
|
|
<pre><code>{
|
|
"targets": [
|
|
{
|
|
"target_name": "hello",
|
|
"sources": [ "hello.cc" ]
|
|
}
|
|
]
|
|
}</code></pre>
|
|
<p>The next step is to generate the appropriate project build files for the
|
|
current platform. Use <code>node-gyp configure</code> for that.
|
|
|
|
</p>
|
|
<p>Now you will have either a <code>Makefile</code> (on Unix platforms) or a <code>vcxproj</code> file
|
|
(on Windows) in the <code>build/</code> directory. Next invoke the <code>node-gyp build</code>
|
|
command.
|
|
|
|
</p>
|
|
<p>Now you have your compiled <code>.node</code> bindings file! The compiled bindings end up
|
|
in <code>build/Release/</code>.
|
|
|
|
</p>
|
|
<p>You can now use the binary addon in a Node project <code>hello.js</code> by pointing <code>require</code> to
|
|
the recently built <code>hello.node</code> module:
|
|
|
|
</p>
|
|
<pre><code>var addon = require('./build/Release/hello');
|
|
|
|
console.log(addon.hello()); // 'world'</code></pre>
|
|
<p>Please see patterns below for further information or
|
|
</p>
|
|
<p><a href="https://github.com/arturadib/node-qt">https://github.com/arturadib/node-qt</a> for an example in production.
|
|
|
|
|
|
</p>
|
|
<h2>Addon patterns<span><a class="mark" href="#addons_addon_patterns" id="addons_addon_patterns">#</a></span></h2>
|
|
<p>Below are some addon patterns to help you get started. Consult the online
|
|
<a href="http://izs.me/v8-docs/main.html">v8 reference</a> for help with the various v8
|
|
calls, and v8's <a href="http://code.google.com/apis/v8/embed.html">Embedder's Guide</a>
|
|
for an explanation of several concepts used such as handles, scopes,
|
|
function templates, etc.
|
|
|
|
</p>
|
|
<p>In order to use these examples you need to compile them using <code>node-gyp</code>.
|
|
Create the following <code>binding.gyp</code> file:
|
|
|
|
</p>
|
|
<pre><code>{
|
|
"targets": [
|
|
{
|
|
"target_name": "addon",
|
|
"sources": [ "addon.cc" ]
|
|
}
|
|
]
|
|
}</code></pre>
|
|
<p>In cases where there is more than one <code>.cc</code> file, simply add the file name to the
|
|
<code>sources</code> array, e.g.:
|
|
|
|
</p>
|
|
<pre><code>"sources": ["addon.cc", "myexample.cc"]</code></pre>
|
|
<p>Now that you have your <code>binding.gyp</code> ready, you can configure and build the
|
|
addon:
|
|
|
|
</p>
|
|
<pre><code>$ node-gyp configure build</code></pre>
|
|
<h3>Function arguments<span><a class="mark" href="#addons_function_arguments" id="addons_function_arguments">#</a></span></h3>
|
|
<p>The following pattern illustrates how to read arguments from JavaScript
|
|
function calls and return a result. This is the main and only needed source
|
|
<code>addon.cc</code>:
|
|
|
|
</p>
|
|
<pre><code>#define BUILDING_NODE_EXTENSION
|
|
#include <node.h>
|
|
|
|
using namespace v8;
|
|
|
|
Handle<Value> Add(const Arguments& args) {
|
|
HandleScope scope;
|
|
|
|
if (args.Length() < 2) {
|
|
ThrowException(Exception::TypeError(String::New("Wrong number of arguments")));
|
|
return scope.Close(Undefined());
|
|
}
|
|
|
|
if (!args[0]->IsNumber() || !args[1]->IsNumber()) {
|
|
ThrowException(Exception::TypeError(String::New("Wrong arguments")));
|
|
return scope.Close(Undefined());
|
|
}
|
|
|
|
Local<Number> num = Number::New(args[0]->NumberValue() +
|
|
args[1]->NumberValue());
|
|
return scope.Close(num);
|
|
}
|
|
|
|
void Init(Handle<Object> target) {
|
|
target->Set(String::NewSymbol("add"),
|
|
FunctionTemplate::New(Add)->GetFunction());
|
|
}
|
|
|
|
NODE_MODULE(addon, Init)</code></pre>
|
|
<p>You can test it with the following JavaScript snippet:
|
|
|
|
</p>
|
|
<pre><code>var addon = require('./build/Release/addon');
|
|
|
|
console.log( 'This should be eight:', addon.add(3,5) );</code></pre>
|
|
<h3>Callbacks<span><a class="mark" href="#addons_callbacks" id="addons_callbacks">#</a></span></h3>
|
|
<p>You can pass JavaScript functions to a C++ function and execute them from
|
|
there. Here's <code>addon.cc</code>:
|
|
|
|
</p>
|
|
<pre><code>#define BUILDING_NODE_EXTENSION
|
|
#include <node.h>
|
|
|
|
using namespace v8;
|
|
|
|
Handle<Value> RunCallback(const Arguments& args) {
|
|
HandleScope scope;
|
|
|
|
Local<Function> cb = Local<Function>::Cast(args[0]);
|
|
const unsigned argc = 1;
|
|
Local<Value> argv[argc] = { Local<Value>::New(String::New("hello world")) };
|
|
cb->Call(Context::GetCurrent()->Global(), argc, argv);
|
|
|
|
return scope.Close(Undefined());
|
|
}
|
|
|
|
void Init(Handle<Object> target) {
|
|
target->Set(String::NewSymbol("runCallback"),
|
|
FunctionTemplate::New(RunCallback)->GetFunction());
|
|
}
|
|
|
|
NODE_MODULE(addon, Init)</code></pre>
|
|
<p>To test it run the following JavaScript snippet:
|
|
|
|
</p>
|
|
<pre><code>var addon = require('./build/Release/addon');
|
|
|
|
addon.runCallback(function(msg){
|
|
console.log(msg); // 'hello world'
|
|
});</code></pre>
|
|
<h3>Object factory<span><a class="mark" href="#addons_object_factory" id="addons_object_factory">#</a></span></h3>
|
|
<p>You can create and return new objects from within a C++ function with this
|
|
<code>addon.cc</code> pattern, which returns an object with property <code>msg</code> that echoes
|
|
the string passed to <code>createObject()</code>:
|
|
|
|
</p>
|
|
<pre><code>#define BUILDING_NODE_EXTENSION
|
|
#include <node.h>
|
|
|
|
using namespace v8;
|
|
|
|
Handle<Value> CreateObject(const Arguments& args) {
|
|
HandleScope scope;
|
|
|
|
Local<Object> obj = Object::New();
|
|
obj->Set(String::NewSymbol("msg"), args[0]->ToString());
|
|
|
|
return scope.Close(obj);
|
|
}
|
|
|
|
void Init(Handle<Object> target) {
|
|
target->Set(String::NewSymbol("createObject"),
|
|
FunctionTemplate::New(CreateObject)->GetFunction());
|
|
}
|
|
|
|
NODE_MODULE(addon, Init)</code></pre>
|
|
<p>To test it in JavaScript:
|
|
|
|
</p>
|
|
<pre><code>var addon = require('./build/Release/addon');
|
|
|
|
var obj1 = addon.createObject('hello');
|
|
var obj2 = addon.createObject('world');
|
|
console.log(obj1.msg+' '+obj2.msg); // 'hello world'</code></pre>
|
|
<h3>Function factory<span><a class="mark" href="#addons_function_factory" id="addons_function_factory">#</a></span></h3>
|
|
<p>This pattern illustrates how to create and return a JavaScript function that
|
|
wraps a C++ function:
|
|
|
|
</p>
|
|
<pre><code>#define BUILDING_NODE_EXTENSION
|
|
#include <node.h>
|
|
|
|
using namespace v8;
|
|
|
|
Handle<Value> MyFunction(const Arguments& args) {
|
|
HandleScope scope;
|
|
return scope.Close(String::New("hello world"));
|
|
}
|
|
|
|
Handle<Value> CreateFunction(const Arguments& args) {
|
|
HandleScope scope;
|
|
|
|
Local<FunctionTemplate> tpl = FunctionTemplate::New(MyFunction);
|
|
Local<Function> fn = tpl->GetFunction();
|
|
fn->SetName(String::NewSymbol("theFunction")); // omit this to make it anonymous
|
|
|
|
return scope.Close(fn);
|
|
}
|
|
|
|
void Init(Handle<Object> target) {
|
|
target->Set(String::NewSymbol("createFunction"),
|
|
FunctionTemplate::New(CreateFunction)->GetFunction());
|
|
}
|
|
|
|
NODE_MODULE(addon, Init)</code></pre>
|
|
<p>To test:
|
|
|
|
</p>
|
|
<pre><code>var addon = require('./build/Release/addon');
|
|
|
|
var fn = addon.createFunction();
|
|
console.log(fn()); // 'hello world'</code></pre>
|
|
<h3>Wrapping C++ objects<span><a class="mark" href="#addons_wrapping_c_objects" id="addons_wrapping_c_objects">#</a></span></h3>
|
|
<p>Here we will create a wrapper for a C++ object/class <code>MyObject</code> that can be
|
|
instantiated in JavaScript through the <code>new</code> operator. First prepare the main
|
|
module <code>addon.cc</code>:
|
|
|
|
</p>
|
|
<pre><code>#define BUILDING_NODE_EXTENSION
|
|
#include <node.h>
|
|
#include "myobject.h"
|
|
|
|
using namespace v8;
|
|
|
|
void InitAll(Handle<Object> target) {
|
|
MyObject::Init(target);
|
|
}
|
|
|
|
NODE_MODULE(addon, InitAll)</code></pre>
|
|
<p>Then in <code>myobject.h</code> make your wrapper inherit from <code>node::ObjectWrap</code>:
|
|
|
|
</p>
|
|
<pre><code>#ifndef MYOBJECT_H
|
|
#define MYOBJECT_H
|
|
|
|
#include <node.h>
|
|
|
|
class MyObject : public node::ObjectWrap {
|
|
public:
|
|
static void Init(v8::Handle<v8::Object> target);
|
|
|
|
private:
|
|
MyObject();
|
|
~MyObject();
|
|
|
|
static v8::Handle<v8::Value> New(const v8::Arguments& args);
|
|
static v8::Handle<v8::Value> PlusOne(const v8::Arguments& args);
|
|
double counter_;
|
|
};
|
|
|
|
#endif</code></pre>
|
|
<p>And in <code>myobject.cc</code> implement the various methods that you want to expose.
|
|
Here we expose the method <code>plusOne</code> by adding it to the constructor's
|
|
prototype:
|
|
|
|
</p>
|
|
<pre><code>#define BUILDING_NODE_EXTENSION
|
|
#include <node.h>
|
|
#include "myobject.h"
|
|
|
|
using namespace v8;
|
|
|
|
MyObject::MyObject() {};
|
|
MyObject::~MyObject() {};
|
|
|
|
void MyObject::Init(Handle<Object> target) {
|
|
// Prepare constructor template
|
|
Local<FunctionTemplate> tpl = FunctionTemplate::New(New);
|
|
tpl->SetClassName(String::NewSymbol("MyObject"));
|
|
tpl->InstanceTemplate()->SetInternalFieldCount(1);
|
|
// Prototype
|
|
tpl->PrototypeTemplate()->Set(String::NewSymbol("plusOne"),
|
|
FunctionTemplate::New(PlusOne)->GetFunction());
|
|
|
|
Persistent<Function> constructor = Persistent<Function>::New(tpl->GetFunction());
|
|
target->Set(String::NewSymbol("MyObject"), constructor);
|
|
}
|
|
|
|
Handle<Value> MyObject::New(const Arguments& args) {
|
|
HandleScope scope;
|
|
|
|
MyObject* obj = new MyObject();
|
|
obj->counter_ = args[0]->IsUndefined() ? 0 : args[0]->NumberValue();
|
|
obj->Wrap(args.This());
|
|
|
|
return args.This();
|
|
}
|
|
|
|
Handle<Value> MyObject::PlusOne(const Arguments& args) {
|
|
HandleScope scope;
|
|
|
|
MyObject* obj = ObjectWrap::Unwrap<MyObject>(args.This());
|
|
obj->counter_ += 1;
|
|
|
|
return scope.Close(Number::New(obj->counter_));
|
|
}</code></pre>
|
|
<p>Test it with:
|
|
|
|
</p>
|
|
<pre><code>var addon = require('./build/Release/addon');
|
|
|
|
var obj = new addon.MyObject(10);
|
|
console.log( obj.plusOne() ); // 11
|
|
console.log( obj.plusOne() ); // 12
|
|
console.log( obj.plusOne() ); // 13</code></pre>
|
|
<h3>Factory of wrapped objects<span><a class="mark" href="#addons_factory_of_wrapped_objects" id="addons_factory_of_wrapped_objects">#</a></span></h3>
|
|
<p>This is useful when you want to be able to create native objects without
|
|
explicitly instantiating them with the <code>new</code> operator in JavaScript, e.g.
|
|
|
|
</p>
|
|
<pre><code>var obj = addon.createObject();
|
|
// instead of:
|
|
// var obj = new addon.Object();</code></pre>
|
|
<p>Let's register our <code>createObject</code> method in <code>addon.cc</code>:
|
|
|
|
</p>
|
|
<pre><code>#define BUILDING_NODE_EXTENSION
|
|
#include <node.h>
|
|
#include "myobject.h"
|
|
|
|
using namespace v8;
|
|
|
|
Handle<Value> CreateObject(const Arguments& args) {
|
|
HandleScope scope;
|
|
return scope.Close(MyObject::NewInstance(args));
|
|
}
|
|
|
|
void InitAll(Handle<Object> target) {
|
|
MyObject::Init();
|
|
|
|
target->Set(String::NewSymbol("createObject"),
|
|
FunctionTemplate::New(CreateObject)->GetFunction());
|
|
}
|
|
|
|
NODE_MODULE(addon, InitAll)</code></pre>
|
|
<p>In <code>myobject.h</code> we now introduce the static method <code>NewInstance</code> that takes
|
|
care of instantiating the object (i.e. it does the job of <code>new</code> in JavaScript):
|
|
|
|
</p>
|
|
<pre><code>#define BUILDING_NODE_EXTENSION
|
|
#ifndef MYOBJECT_H
|
|
#define MYOBJECT_H
|
|
|
|
#include <node.h>
|
|
|
|
class MyObject : public node::ObjectWrap {
|
|
public:
|
|
static void Init();
|
|
static v8::Handle<v8::Value> NewInstance(const v8::Arguments& args);
|
|
|
|
private:
|
|
MyObject();
|
|
~MyObject();
|
|
|
|
static v8::Persistent<v8::Function> constructor;
|
|
static v8::Handle<v8::Value> New(const v8::Arguments& args);
|
|
static v8::Handle<v8::Value> PlusOne(const v8::Arguments& args);
|
|
double counter_;
|
|
};
|
|
|
|
#endif</code></pre>
|
|
<p>The implementation is similar to the above in <code>myobject.cc</code>:
|
|
|
|
</p>
|
|
<pre><code>#define BUILDING_NODE_EXTENSION
|
|
#include <node.h>
|
|
#include "myobject.h"
|
|
|
|
using namespace v8;
|
|
|
|
MyObject::MyObject() {};
|
|
MyObject::~MyObject() {};
|
|
|
|
Persistent<Function> MyObject::constructor;
|
|
|
|
void MyObject::Init() {
|
|
// Prepare constructor template
|
|
Local<FunctionTemplate> tpl = FunctionTemplate::New(New);
|
|
tpl->SetClassName(String::NewSymbol("MyObject"));
|
|
tpl->InstanceTemplate()->SetInternalFieldCount(1);
|
|
// Prototype
|
|
tpl->PrototypeTemplate()->Set(String::NewSymbol("plusOne"),
|
|
FunctionTemplate::New(PlusOne)->GetFunction());
|
|
|
|
constructor = Persistent<Function>::New(tpl->GetFunction());
|
|
}
|
|
|
|
Handle<Value> MyObject::New(const Arguments& args) {
|
|
HandleScope scope;
|
|
|
|
MyObject* obj = new MyObject();
|
|
obj->counter_ = args[0]->IsUndefined() ? 0 : args[0]->NumberValue();
|
|
obj->Wrap(args.This());
|
|
|
|
return args.This();
|
|
}
|
|
|
|
Handle<Value> MyObject::NewInstance(const Arguments& args) {
|
|
HandleScope scope;
|
|
|
|
const unsigned argc = 1;
|
|
Handle<Value> argv[argc] = { args[0] };
|
|
Local<Object> instance = constructor->NewInstance(argc, argv);
|
|
|
|
return scope.Close(instance);
|
|
}
|
|
|
|
Handle<Value> MyObject::PlusOne(const Arguments& args) {
|
|
HandleScope scope;
|
|
|
|
MyObject* obj = ObjectWrap::Unwrap<MyObject>(args.This());
|
|
obj->counter_ += 1;
|
|
|
|
return scope.Close(Number::New(obj->counter_));
|
|
}</code></pre>
|
|
<p>Test it with:
|
|
|
|
</p>
|
|
<pre><code>var addon = require('./build/Release/addon');
|
|
|
|
var obj = addon.createObject(10);
|
|
console.log( obj.plusOne() ); // 11
|
|
console.log( obj.plusOne() ); // 12
|
|
console.log( obj.plusOne() ); // 13
|
|
|
|
var obj2 = addon.createObject(20);
|
|
console.log( obj2.plusOne() ); // 21
|
|
console.log( obj2.plusOne() ); // 22
|
|
console.log( obj2.plusOne() ); // 23</code></pre>
|
|
<h3>Passing wrapped objects around<span><a class="mark" href="#addons_passing_wrapped_objects_around" id="addons_passing_wrapped_objects_around">#</a></span></h3>
|
|
<p>In addition to wrapping and returning C++ objects, you can pass them around
|
|
by unwrapping them with Node's <code>node::ObjectWrap::Unwrap</code> helper function.
|
|
In the following <code>addon.cc</code> we introduce a function <code>add()</code> that can take on two
|
|
<code>MyObject</code> objects:
|
|
|
|
</p>
|
|
<pre><code>#define BUILDING_NODE_EXTENSION
|
|
#include <node.h>
|
|
#include "myobject.h"
|
|
|
|
using namespace v8;
|
|
|
|
Handle<Value> CreateObject(const Arguments& args) {
|
|
HandleScope scope;
|
|
return scope.Close(MyObject::NewInstance(args));
|
|
}
|
|
|
|
Handle<Value> Add(const Arguments& args) {
|
|
HandleScope scope;
|
|
|
|
MyObject* obj1 = node::ObjectWrap::Unwrap<MyObject>(
|
|
args[0]->ToObject());
|
|
MyObject* obj2 = node::ObjectWrap::Unwrap<MyObject>(
|
|
args[1]->ToObject());
|
|
|
|
double sum = obj1->Val() + obj2->Val();
|
|
return scope.Close(Number::New(sum));
|
|
}
|
|
|
|
void InitAll(Handle<Object> target) {
|
|
MyObject::Init();
|
|
|
|
target->Set(String::NewSymbol("createObject"),
|
|
FunctionTemplate::New(CreateObject)->GetFunction());
|
|
|
|
target->Set(String::NewSymbol("add"),
|
|
FunctionTemplate::New(Add)->GetFunction());
|
|
}
|
|
|
|
NODE_MODULE(addon, InitAll)</code></pre>
|
|
<p>To make things interesting we introduce a public method in <code>myobject.h</code> so we
|
|
can probe private values after unwrapping the object:
|
|
|
|
</p>
|
|
<pre><code>#define BUILDING_NODE_EXTENSION
|
|
#ifndef MYOBJECT_H
|
|
#define MYOBJECT_H
|
|
|
|
#include <node.h>
|
|
|
|
class MyObject : public node::ObjectWrap {
|
|
public:
|
|
static void Init();
|
|
static v8::Handle<v8::Value> NewInstance(const v8::Arguments& args);
|
|
double Val() const { return val_; }
|
|
|
|
private:
|
|
MyObject();
|
|
~MyObject();
|
|
|
|
static v8::Persistent<v8::Function> constructor;
|
|
static v8::Handle<v8::Value> New(const v8::Arguments& args);
|
|
double val_;
|
|
};
|
|
|
|
#endif</code></pre>
|
|
<p>The implementation of <code>myobject.cc</code> is similar as before:
|
|
|
|
</p>
|
|
<pre><code>#define BUILDING_NODE_EXTENSION
|
|
#include <node.h>
|
|
#include "myobject.h"
|
|
|
|
using namespace v8;
|
|
|
|
MyObject::MyObject() {};
|
|
MyObject::~MyObject() {};
|
|
|
|
Persistent<Function> MyObject::constructor;
|
|
|
|
void MyObject::Init() {
|
|
// Prepare constructor template
|
|
Local<FunctionTemplate> tpl = FunctionTemplate::New(New);
|
|
tpl->SetClassName(String::NewSymbol("MyObject"));
|
|
tpl->InstanceTemplate()->SetInternalFieldCount(1);
|
|
|
|
constructor = Persistent<Function>::New(tpl->GetFunction());
|
|
}
|
|
|
|
Handle<Value> MyObject::New(const Arguments& args) {
|
|
HandleScope scope;
|
|
|
|
MyObject* obj = new MyObject();
|
|
obj->val_ = args[0]->IsUndefined() ? 0 : args[0]->NumberValue();
|
|
obj->Wrap(args.This());
|
|
|
|
return args.This();
|
|
}
|
|
|
|
Handle<Value> MyObject::NewInstance(const Arguments& args) {
|
|
HandleScope scope;
|
|
|
|
const unsigned argc = 1;
|
|
Handle<Value> argv[argc] = { args[0] };
|
|
Local<Object> instance = constructor->NewInstance(argc, argv);
|
|
|
|
return scope.Close(instance);
|
|
}</code></pre>
|
|
<p>Test it with:
|
|
|
|
</p>
|
|
<pre><code>var addon = require('./build/Release/addon');
|
|
|
|
var obj1 = addon.createObject(10);
|
|
var obj2 = addon.createObject(20);
|
|
var result = addon.add(obj1, obj2);
|
|
|
|
console.log(result); // 30</code></pre>
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div id="footer">
|
|
<ul class="clearfix">
|
|
<li><a href="/">Node.js</a></li>
|
|
<li><a href="/download/">Download</a></li>
|
|
<li><a href="/about/">About</a></li>
|
|
<li><a href="http://search.npmjs.org/">npm Registry</a></li>
|
|
<li><a href="http://nodejs.org/api/">Docs</a></li>
|
|
<li><a href="http://blog.nodejs.org">Blog</a></li>
|
|
<li><a href="/community/">Community</a></li>
|
|
<li><a href="/logos/">Logos</a></li>
|
|
<li><a href="http://jobs.nodejs.org/">Jobs</a></li>
|
|
<li><a href="http://twitter.com/nodejs" class="twitter">@nodejs</a></li>
|
|
</ul>
|
|
|
|
<p>Copyright <a href="http://joyent.com/">Joyent, Inc</a>, Node.js is a <a href="/trademark-policy.pdf">trademark</a> of Joyent, Inc. View <a href="https://raw.github.com/joyent/node/v0.8.14/LICENSE">license</a>.</p>
|
|
</div>
|
|
|
|
<script src="../sh_main.js"></script>
|
|
<script src="../sh_javascript.min.js"></script>
|
|
<script>highlight(undefined, undefined, 'pre');</script>
|
|
<script>
|
|
window._gaq = [['_setAccount', 'UA-10874194-2'], ['_trackPageview']];
|
|
(function(d, t) {
|
|
var g = d.createElement(t),
|
|
s = d.getElementsByTagName(t)[0];
|
|
g.src = '//www.google-analytics.com/ga.js';
|
|
s.parentNode.insertBefore(g, s);
|
|
}(document, 'script'));
|
|
</script>
|
|
</body>
|
|
</html>
|
|
|