Server IP : 127.0.0.2 / Your IP : 13.58.229.23 Web Server : Apache/2.4.18 (Ubuntu) System : User : www-data ( ) PHP Version : 7.0.33-0ubuntu0.16.04.16 Disable Function : disk_free_space,disk_total_space,diskfreespace,dl,exec,fpaththru,getmyuid,getmypid,highlight_file,ignore_user_abord,leak,listen,link,opcache_get_configuration,opcache_get_status,passthru,pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,php_uname,phpinfo,posix_ctermid,posix_getcwd,posix_getegid,posix_geteuid,posix_getgid,posix_getgrgid,posix_getgrnam,posix_getgroups,posix_getlogin,posix_getpgid,posix_getpgrp,posix_getpid,posix,_getppid,posix_getpwnam,posix_getpwuid,posix_getrlimit,posix_getsid,posix_getuid,posix_isatty,posix_kill,posix_mkfifo,posix_setegid,posix_seteuid,posix_setgid,posix_setpgid,posix_setsid,posix_setuid,posix_times,posix_ttyname,posix_uname,pclose,popen,proc_open,proc_close,proc_get_status,proc_nice,proc_terminate,shell_exec,source,show_source,system,virtual MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON | Sudo : ON | Pkexec : ON Directory : /usr/share/doc/nodejs/api/ |
Upload File : |
<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <title>Addons Node.js v4.2.6 Manual & Documentation</title> <link rel="stylesheet" href="assets/style.css"> <link rel="stylesheet" href="assets/sh.css"> <link rel="canonical" href="addons.html"> </head> <body class="alt apidoc" id="api-section-addons"> <div id="content" class="clearfix"> <div id="column2" class="interior"> <div id="intro" class="interior"> <a href="/" title="Go back to the home page"> Node.js (1) </a> </div> <ul> <li><a class="nav-documentation" href="documentation.html">About these Docs</a></li> <li><a class="nav-synopsis" href="synopsis.html">Synopsis</a></li> <li><a class="nav-assert" href="assert.html">Assertion Testing</a></li> <li><a class="nav-buffer" href="buffer.html">Buffer</a></li> <li><a class="nav-addons active" href="addons.html">C/C++ Addons</a></li> <li><a class="nav-child_process" href="child_process.html">Child Processes</a></li> <li><a class="nav-cluster" href="cluster.html">Cluster</a></li> <li><a class="nav-console" href="console.html">Console</a></li> <li><a class="nav-crypto" href="crypto.html">Crypto</a></li> <li><a class="nav-debugger" href="debugger.html">Debugger</a></li> <li><a class="nav-dns" href="dns.html">DNS</a></li> <li><a class="nav-domain" href="domain.html">Domain</a></li> <li><a class="nav-errors" href="errors.html">Errors</a></li> <li><a class="nav-events" href="events.html">Events</a></li> <li><a class="nav-fs" href="fs.html">File System</a></li> <li><a class="nav-globals" href="globals.html">Globals</a></li> <li><a class="nav-http" href="http.html">HTTP</a></li> <li><a class="nav-https" href="https.html">HTTPS</a></li> <li><a class="nav-modules" href="modules.html">Modules</a></li> <li><a class="nav-net" href="net.html">Net</a></li> <li><a class="nav-os" href="os.html">OS</a></li> <li><a class="nav-path" href="path.html">Path</a></li> <li><a class="nav-process" href="process.html">Process</a></li> <li><a class="nav-punycode" href="punycode.html">Punycode</a></li> <li><a class="nav-querystring" href="querystring.html">Query Strings</a></li> <li><a class="nav-readline" href="readline.html">Readline</a></li> <li><a class="nav-repl" href="repl.html">REPL</a></li> <li><a class="nav-stream" href="stream.html">Stream</a></li> <li><a class="nav-string_decoder" href="string_decoder.html">String Decoder</a></li> <li><a class="nav-timers" href="timers.html">Timers</a></li> <li><a class="nav-tls" href="tls.html">TLS/SSL</a></li> <li><a class="nav-tty" href="tty.html">TTY</a></li> <li><a class="nav-dgram" href="dgram.html">UDP/Datagram</a></li> <li><a class="nav-url" href="url.html">URL</a></li> <li><a class="nav-util" href="util.html">Utilities</a></li> <li><a class="nav-v8" href="v8.html">V8</a></li> <li><a class="nav-vm" href="vm.html">VM</a></li> <li><a class="nav-zlib" href="zlib.html">ZLIB</a></li> </ul> </div> <div id="column1" data-id="addons" class="interior"> <header> <h1>Node.js v4.2.6 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> <li><a href="#addons_atexit_hooks">AtExit hooks</a><ul> <li><a href="#addons_void_atexit_callback_args">void AtExit(callback, args)</a></li> </ul> </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.js source tree), which is also available <a href="https://v8docs.nodesource.com/">online</a>.</p> </li> <li><p><a href="https://github.com/libuv/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 be 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.js libraries. The most important class is <code>node::ObjectWrap</code> 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.js 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> <p>All of the following examples are available for <a href="https://github.com/nodejs/node-addon-examples">download</a> and may be used as a starting-point for your own Addon. </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>module.exports.hello = function() { return 'world'; };</code></pre> <p>First we create a file <code>hello.cc</code>: </p> <pre><code>// hello.cc #include <node.h> namespace demo { using v8::FunctionCallbackInfo; using v8::Isolate; using v8::Local; using v8::Object; using v8::String; using v8::Value; void Method(const FunctionCallbackInfo<Value>& args) { Isolate* isolate = args.GetIsolate(); args.GetReturnValue().Set(String::NewFromUtf8(isolate, "world")); } void init(Local<Object> exports) { NODE_SET_METHOD(exports, "hello", Method); } NODE_MODULE(addon, init) } // namespace demo</code></pre> <p>Note that all Node.js addons must export an initialization function: </p> <pre><code>void Initialize(Local<Object> exports); 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 (excluding the .node suffix). </p> <p>The source code needs to be built into <code>addon.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/nodejs/node-gyp">node-gyp</a>. </p> <pre><code>{ "targets": [ { "target_name": "addon", "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.js project <code>hello.js</code> by pointing <code>require</code> to the recently built <code>hello.node</code> module: </p> <pre><code>// hello.js const addon = require('./build/Release/addon'); 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="https://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. For example: </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>// addon.cc #include <node.h> namespace demo { using v8::Exception; using v8::FunctionCallbackInfo; using v8::Isolate; using v8::Local; using v8::Number; using v8::Object; using v8::String; using v8::Value; void Add(const FunctionCallbackInfo<Value>& args) { Isolate* isolate = args.GetIsolate(); if (args.Length() < 2) { isolate->ThrowException(Exception::TypeError( String::NewFromUtf8(isolate, "Wrong number of arguments"))); return; } if (!args[0]->IsNumber() || !args[1]->IsNumber()) { isolate->ThrowException(Exception::TypeError( String::NewFromUtf8(isolate, "Wrong arguments"))); return; } double value = args[0]->NumberValue() + args[1]->NumberValue(); Local<Number> num = Number::New(isolate, value); args.GetReturnValue().Set(num); } void Init(Local<Object> exports) { NODE_SET_METHOD(exports, "add", Add); } NODE_MODULE(addon, Init) } // namespace demo</code></pre> <p>You can test it with the following JavaScript snippet: </p> <pre><code>// test.js const 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>// addon.cc #include <node.h> namespace demo { using v8::Function; using v8::FunctionCallbackInfo; using v8::Isolate; using v8::Local; using v8::Null; using v8::Object; using v8::String; using v8::Value; void RunCallback(const FunctionCallbackInfo<Value>& args) { Isolate* isolate = args.GetIsolate(); Local<Function> cb = Local<Function>::Cast(args[0]); const unsigned argc = 1; Local<Value> argv[argc] = { String::NewFromUtf8(isolate, "hello world") }; cb->Call(Null(isolate), argc, argv); } void Init(Local<Object> exports, Local<Object> module) { NODE_SET_METHOD(module, "exports", RunCallback); } NODE_MODULE(addon, Init) } // namespace demo</code></pre> <p>Note that this example uses a two-argument form of <code>Init()</code> that receives the full <code>module</code> object as the second argument. This allows the addon to completely overwrite <code>exports</code> with a single function instead of adding the function as a property of <code>exports</code>. </p> <p>To test it, run the following JavaScript snippet: </p> <pre><code>// test.js const addon = require('./build/Release/addon'); addon(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>// addon.cc #include <node.h> namespace demo { using v8::FunctionCallbackInfo; using v8::Isolate; using v8::Local; using v8::Object; using v8::String; using v8::Value; void CreateObject(const FunctionCallbackInfo<Value>& args) { Isolate* isolate = args.GetIsolate(); Local<Object> obj = Object::New(isolate); obj->Set(String::NewFromUtf8(isolate, "msg"), args[0]->ToString()); args.GetReturnValue().Set(obj); } void Init(Local<Object> exports, Local<Object> module) { NODE_SET_METHOD(module, "exports", CreateObject); } NODE_MODULE(addon, Init) } // namespace demo</code></pre> <p>To test it in JavaScript: </p> <pre><code>// test.js const addon = require('./build/Release/addon'); var obj1 = addon('hello'); var obj2 = addon('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>// addon.cc #include <node.h> namespace demo { using v8::Function; using v8::FunctionCallbackInfo; using v8::FunctionTemplate; using v8::Isolate; using v8::Local; using v8::Object; using v8::String; using v8::Value; void MyFunction(const FunctionCallbackInfo<Value>& args) { Isolate* isolate = args.GetIsolate(); args.GetReturnValue().Set(String::NewFromUtf8(isolate, "hello world")); } void CreateFunction(const FunctionCallbackInfo<Value>& args) { Isolate* isolate = args.GetIsolate(); Local<FunctionTemplate> tpl = FunctionTemplate::New(isolate, MyFunction); Local<Function> fn = tpl->GetFunction(); // omit this to make it anonymous fn->SetName(String::NewFromUtf8(isolate, "theFunction")); args.GetReturnValue().Set(fn); } void Init(Local<Object> exports, Local<Object> module) { NODE_SET_METHOD(module, "exports", CreateFunction); } NODE_MODULE(addon, Init) } // namespace demo</code></pre> <p>To test: </p> <pre><code>// test.js const addon = require('./build/Release/addon'); var fn = addon(); 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>// addon.cc #include <node.h> #include "myobject.h" namespace demo { using v8::Local; using v8::Object; void InitAll(Local<Object> exports) { MyObject::Init(exports); } NODE_MODULE(addon, InitAll) } // namespace demo</code></pre> <p>Then, in <code>myobject.h</code>, make your wrapper inherit from <code>node::ObjectWrap</code>: </p> <pre><code>// myobject.h #ifndef MYOBJECT_H #define MYOBJECT_H #include <node.h> #include <node_object_wrap.h> namespace demo { class MyObject : public node::ObjectWrap { public: static void Init(v8::Local<v8::Object> exports); private: explicit MyObject(double value = 0); ~MyObject(); static void New(const v8::FunctionCallbackInfo<v8::Value>& args); static void PlusOne(const v8::FunctionCallbackInfo<v8::Value>& args); static v8::Persistent<v8::Function> constructor; double value_; }; } // namespace demo #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>// myobject.cc #include "myobject.h" namespace demo { using v8::Function; using v8::FunctionCallbackInfo; using v8::FunctionTemplate; using v8::Isolate; using v8::Local; using v8::Number; using v8::Object; using v8::Persistent; using v8::String; using v8::Value; Persistent<Function> MyObject::constructor; MyObject::MyObject(double value) : value_(value) { } MyObject::~MyObject() { } void MyObject::Init(Local<Object> exports) { Isolate* isolate = exports->GetIsolate(); // Prepare constructor template Local<FunctionTemplate> tpl = FunctionTemplate::New(isolate, New); tpl->SetClassName(String::NewFromUtf8(isolate, "MyObject")); tpl->InstanceTemplate()->SetInternalFieldCount(1); // Prototype NODE_SET_PROTOTYPE_METHOD(tpl, "plusOne", PlusOne); constructor.Reset(isolate, tpl->GetFunction()); exports->Set(String::NewFromUtf8(isolate, "MyObject"), tpl->GetFunction()); } void MyObject::New(const FunctionCallbackInfo<Value>& args) { Isolate* isolate = args.GetIsolate(); if (args.IsConstructCall()) { // Invoked as constructor: `new MyObject(...)` double value = args[0]->IsUndefined() ? 0 : args[0]->NumberValue(); MyObject* obj = new MyObject(value); obj->Wrap(args.This()); args.GetReturnValue().Set(args.This()); } else { // Invoked as plain function `MyObject(...)`, turn into construct call. const int argc = 1; Local<Value> argv[argc] = { args[0] }; Local<Function> cons = Local<Function>::New(isolate, constructor); args.GetReturnValue().Set(cons->NewInstance(argc, argv)); } } void MyObject::PlusOne(const FunctionCallbackInfo<Value>& args) { Isolate* isolate = args.GetIsolate(); MyObject* obj = ObjectWrap::Unwrap<MyObject>(args.Holder()); obj->value_ += 1; args.GetReturnValue().Set(Number::New(isolate, obj->value_)); } } // namespace demo</code></pre> <p>Test it with: </p> <pre><code>// test.js const 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. For example: </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>// addon.cc #include <node.h> #include "myobject.h" namespace demo { using v8::FunctionCallbackInfo; using v8::Isolate; using v8::Local; using v8::Object; using v8::String; using v8::Value; void CreateObject(const FunctionCallbackInfo<Value>& args) { MyObject::NewInstance(args); } void InitAll(Local<Object> exports, Local<Object> module) { MyObject::Init(exports->GetIsolate()); NODE_SET_METHOD(module, "exports", CreateObject); } NODE_MODULE(addon, InitAll) } // namespace demo</code></pre> <p>In <code>myobject.h</code>, we now introduce the static method <code>NewInstance</code> that takes care of instantiating the object. In other words, it does the job of <code>new</code> in JavaScript: </p> <pre><code>// myobject.h #ifndef MYOBJECT_H #define MYOBJECT_H #include <node.h> #include <node_object_wrap.h> namespace demo { class MyObject : public node::ObjectWrap { public: static void Init(v8::Isolate* isolate); static void NewInstance(const v8::FunctionCallbackInfo<v8::Value>& args); private: explicit MyObject(double value = 0); ~MyObject(); static void New(const v8::FunctionCallbackInfo<v8::Value>& args); static void PlusOne(const v8::FunctionCallbackInfo<v8::Value>& args); static v8::Persistent<v8::Function> constructor; double value_; }; } // namespace demo #endif</code></pre> <p>The implementation is similar to the above in <code>myobject.cc</code>: </p> <pre><code>// myobject.cc #include <node.h> #include "myobject.h" namespace demo { using v8::Function; using v8::FunctionCallbackInfo; using v8::FunctionTemplate; using v8::Isolate; using v8::Local; using v8::Number; using v8::Object; using v8::Persistent; using v8::String; using v8::Value; Persistent<Function> MyObject::constructor; MyObject::MyObject(double value) : value_(value) { } MyObject::~MyObject() { } void MyObject::Init(Isolate* isolate) { // Prepare constructor template Local<FunctionTemplate> tpl = FunctionTemplate::New(isolate, New); tpl->SetClassName(String::NewFromUtf8(isolate, "MyObject")); tpl->InstanceTemplate()->SetInternalFieldCount(1); // Prototype NODE_SET_PROTOTYPE_METHOD(tpl, "plusOne", PlusOne); constructor.Reset(isolate, tpl->GetFunction()); } void MyObject::New(const FunctionCallbackInfo<Value>& args) { Isolate* isolate = args.GetIsolate(); if (args.IsConstructCall()) { // Invoked as constructor: `new MyObject(...)` double value = args[0]->IsUndefined() ? 0 : args[0]->NumberValue(); MyObject* obj = new MyObject(value); obj->Wrap(args.This()); args.GetReturnValue().Set(args.This()); } else { // Invoked as plain function `MyObject(...)`, turn into construct call. const int argc = 1; Local<Value> argv[argc] = { args[0] }; Local<Function> cons = Local<Function>::New(isolate, constructor); args.GetReturnValue().Set(cons->NewInstance(argc, argv)); } } void MyObject::NewInstance(const FunctionCallbackInfo<Value>& args) { Isolate* isolate = args.GetIsolate(); const unsigned argc = 1; Local<Value> argv[argc] = { args[0] }; Local<Function> cons = Local<Function>::New(isolate, constructor); Local<Object> instance = cons->NewInstance(argc, argv); args.GetReturnValue().Set(instance); } void MyObject::PlusOne(const FunctionCallbackInfo<Value>& args) { Isolate* isolate = args.GetIsolate(); MyObject* obj = ObjectWrap::Unwrap<MyObject>(args.Holder()); obj->value_ += 1; args.GetReturnValue().Set(Number::New(isolate, obj->value_)); } } // namespace demo</code></pre> <p>Test it with: </p> <pre><code>// test.js const createObject = require('./build/Release/addon'); var obj = createObject(10); console.log( obj.plusOne() ); // 11 console.log( obj.plusOne() ); // 12 console.log( obj.plusOne() ); // 13 var obj2 = 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 the Node.js helper function <code>node::ObjectWrap::Unwrap</code>. 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>// addon.cc #include <node.h> #include <node_object_wrap.h> #include "myobject.h" namespace demo { using v8::FunctionCallbackInfo; using v8::Isolate; using v8::Local; using v8::Number; using v8::Object; using v8::String; using v8::Value; void CreateObject(const FunctionCallbackInfo<Value>& args) { MyObject::NewInstance(args); } void Add(const FunctionCallbackInfo<Value>& args) { Isolate* isolate = args.GetIsolate(); MyObject* obj1 = node::ObjectWrap::Unwrap<MyObject>( args[0]->ToObject()); MyObject* obj2 = node::ObjectWrap::Unwrap<MyObject>( args[1]->ToObject()); double sum = obj1->value() + obj2->value(); args.GetReturnValue().Set(Number::New(isolate, sum)); } void InitAll(Local<Object> exports) { MyObject::Init(exports->GetIsolate()); NODE_SET_METHOD(exports, "createObject", CreateObject); NODE_SET_METHOD(exports, "add", Add); } NODE_MODULE(addon, InitAll) } // namespace demo</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>// myobject.h #ifndef MYOBJECT_H #define MYOBJECT_H #include <node.h> #include <node_object_wrap.h> namespace demo { class MyObject : public node::ObjectWrap { public: static void Init(v8::Isolate* isolate); static void NewInstance(const v8::FunctionCallbackInfo<v8::Value>& args); inline double value() const { return value_; } private: explicit MyObject(double value = 0); ~MyObject(); static void New(const v8::FunctionCallbackInfo<v8::Value>& args); static v8::Persistent<v8::Function> constructor; double value_; }; } // namespace demo #endif</code></pre> <p>The implementation of <code>myobject.cc</code> is similar to before: </p> <pre><code>// myobject.cc #include <node.h> #include "myobject.h" namespace demo { using v8::Function; using v8::FunctionCallbackInfo; using v8::FunctionTemplate; using v8::Isolate; using v8::Local; using v8::Object; using v8::Persistent; using v8::String; using v8::Value; Persistent<Function> MyObject::constructor; MyObject::MyObject(double value) : value_(value) { } MyObject::~MyObject() { } void MyObject::Init(Isolate* isolate) { // Prepare constructor template Local<FunctionTemplate> tpl = FunctionTemplate::New(isolate, New); tpl->SetClassName(String::NewFromUtf8(isolate, "MyObject")); tpl->InstanceTemplate()->SetInternalFieldCount(1); constructor.Reset(isolate, tpl->GetFunction()); } void MyObject::New(const FunctionCallbackInfo<Value>& args) { Isolate* isolate = args.GetIsolate(); if (args.IsConstructCall()) { // Invoked as constructor: `new MyObject(...)` double value = args[0]->IsUndefined() ? 0 : args[0]->NumberValue(); MyObject* obj = new MyObject(value); obj->Wrap(args.This()); args.GetReturnValue().Set(args.This()); } else { // Invoked as plain function `MyObject(...)`, turn into construct call. const int argc = 1; Local<Value> argv[argc] = { args[0] }; Local<Function> cons = Local<Function>::New(isolate, constructor); args.GetReturnValue().Set(cons->NewInstance(argc, argv)); } } void MyObject::NewInstance(const FunctionCallbackInfo<Value>& args) { Isolate* isolate = args.GetIsolate(); const unsigned argc = 1; Local<Value> argv[argc] = { args[0] }; Local<Function> cons = Local<Function>::New(isolate, constructor); Local<Object> instance = cons->NewInstance(argc, argv); args.GetReturnValue().Set(instance); } } // namespace demo</code></pre> <p>Test it with: </p> <pre><code>// test.js const 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> <h3>AtExit hooks<span><a class="mark" href="#addons_atexit_hooks" id="addons_atexit_hooks">#</a></span></h3> <h4>void AtExit(callback, args)<span><a class="mark" href="#addons_void_atexit_callback_args" id="addons_void_atexit_callback_args">#</a></span></h4> <ul> <li><code>callback</code>: <code>void (*)(void*)</code> - A pointer to the function to call at exit.</li> <li><code>args</code>: <code>void*</code> - A pointer to pass to the callback at exit.</li> </ul> <p>Registers exit hooks that run after the event loop has ended but before the VM is killed. </p> <p>Callbacks are run in last-in first-out order. AtExit takes two parameters: a pointer to a callback function to run at exit, and a pointer to untyped context data to be passed to that callback. </p> <p>The file <code>addon.cc</code> implements AtExit below: </p> <pre><code>// addon.cc #undef NDEBUG #include <assert.h> #include <stdlib.h> #include <node.h> namespace demo { using node::AtExit; using v8::HandleScope; using v8::Isolate; using v8::Local; using v8::Object; static char cookie[] = "yum yum"; static int at_exit_cb1_called = 0; static int at_exit_cb2_called = 0; static void at_exit_cb1(void* arg) { Isolate* isolate = static_cast<Isolate*>(arg); HandleScope scope(isolate); Local<Object> obj = Object::New(isolate); assert(!obj.IsEmpty()); // assert VM is still alive assert(obj->IsObject()); at_exit_cb1_called++; } static void at_exit_cb2(void* arg) { assert(arg == static_cast<void*>(cookie)); at_exit_cb2_called++; } static void sanity_check(void*) { assert(at_exit_cb1_called == 1); assert(at_exit_cb2_called == 2); } void init(Local<Object> exports) { AtExit(sanity_check); AtExit(at_exit_cb2, cookie); AtExit(at_exit_cb2, cookie); AtExit(at_exit_cb1, exports->GetIsolate()); } NODE_MODULE(addon, init); } // namespace demo</code></pre> <p>Test in JavaScript by running: </p> <pre><code>// test.js const addon = require('./build/Release/addon');</code></pre> </div> </div> </div> <script src="assets/sh_main.js"></script> <script src="assets/sh_javascript.min.js"></script> <script>highlight(undefined, undefined, 'pre');</script> </body> </html>