參考: http://nodejs.cn/api/addons.html
NodeJs調用Dll中的類或者函數接口有一套基於V8的框架,有固定的寫法:
註冊入口函數,js在require的時候會調用該註冊接口
Param1: 註冊名稱,無特殊要求
Param2: js第一次加載模塊時調用的函數接口,一般用於註冊給js調用的接口,或者初始化函數
NODE_MODULE(NODE_MODULE_NAME_YPP, Init);
初始化接口固定參數類型 v8::Local<v8::Object>
void Init(v8::Local<v8::Object> exports)
在初始化函數中註冊給js調用的接口:
//Param1:exports
//Param2:給js調用的接口名
//Param3:對應的C++函數名
NODE_SET_METHOD(exports, "PRINT", JsPrint);
註冊給js調用的類對象:
//生成新的函數模板,指定JS構造時對應的C++函數未JsInit
auto isolate = exports->GetIsolate();
v8::Local<v8::FunctionTemplate> tpl = v8::FunctionTemplate::New(isolate, JSInit);
//設置fieldcount爲1
tpl->InstanceTemplate()->SetInternalFieldCount(1);
//爲該函數對象掛接成員函數,可以是普通函數,也可以是類靜態成員函數
NODE_SET_PROTOTYPE_METHOD(tpl, "Print",JsPrint);
//獲取函數對象
auto JsConstruct = tpl->GetFunction(isolate->GetCurrentContext()).ToLocalChecked();
//將函數對象設置給Js調用
exports->Set(isolate->GetCurrentContext(), v8::String::NewFromUtf8(isolate, "Test"),
JsConstruct);
Ps:實際上就是模擬了一個類給js調用
具體js調用對應C++函數接口形式:
//Param1: const v8::FunctionCallbackInfo<v8::Value>&
static void JsPrint(const v8::FunctionCallbackInfo<v8::Value>& args)
//可以通過args下標獲取js調用時傳入的參數,並轉化爲C++數據類型
Int number = args[0]->Int32Value(args.GetIsolate()->GetCurrentContext()).FromJust();
符一個可以調用的例子:
#pragma once
#include <node.h>
#include <node_object_wrap.h>
#include <iostream>
#include <uv.h>
namespace nodeCppWrapper
{
struct Data
{
v8::Persistent<v8::Function> callback;
int count;
};
class Test : public node::ObjectWrap
{
public:
static void Init(v8::Local<v8::Object> exports)
{
auto isolate = exports->GetIsolate();
v8::Local<v8::FunctionTemplate> tpl = v8::FunctionTemplate::New(isolate, JSConstruct);
//tpl->SetClassName(v8::String::NewFromUtf8(isolate, "DNS"));
tpl->InstanceTemplate()->SetInternalFieldCount(1);
NODE_SET_PROTOTYPE_METHOD(tpl, "SetNumber", JsSetNumber);
NODE_SET_PROTOTYPE_METHOD(tpl, "Calc", JSCalc);
NODE_SET_METHOD(exports, "PRINT", JsSetNumber);
auto JsConstruct = tpl->GetFunction(isolate->GetCurrentContext()).ToLocalChecked();
exports->Set(isolate->GetCurrentContext(), v8::String::NewFromUtf8(isolate, "Test"),
JsConstruct);
}
private:
Test()
{
}
static void JSConstruct(const v8::FunctionCallbackInfo<v8::Value>& args)
{
auto isolate = args.GetIsolate();
if (args.IsConstructCall())
{
std::cout << "JSConstruct" << std::endl;
auto obj = new Test;
obj->Wrap(args.This());
args.GetReturnValue().Set(args.This());
}
else
{
std::cout << "error.this is contructor, please use new." << std::endl;
}
}
static void JsSetNumber(const v8::FunctionCallbackInfo<v8::Value>& args)
{
int n = args[0]->Int32Value(args.GetIsolate()->GetCurrentContext()).FromJust();
std::cout << "JsSetNumber: " << n << std::endl;
auto test = node::ObjectWrap::Unwrap<Test>(args.Holder());
test->number = n;
args.GetReturnValue().Set(v8::Number::New(args.GetIsolate(), 1));
}
static void calculate(uv_work_t* work) {
auto data = (Data*)work->data;
for (int i=0; i< data->count; ++i)
{
Sleep(1000);
}
}
static void complete(uv_work_t* work)
{
auto isolate = v8::Isolate::GetCurrent();
v8::HandleScope handleScope(isolate);
auto data = (Data*)work->data;
v8::Local<v8::Value> result[1] = { v8::String::NewFromUtf8(isolate,"calc finish.") };
v8::Local<v8::Function> cb = v8::Local<v8::Function>::New(isolate, data->callback);
cb->Call(isolate->GetCurrentContext(), Null(isolate),1, result);
data->callback.Reset();
delete data;
delete work;
}
static void JSCalc(const v8::FunctionCallbackInfo<v8::Value>& args)
{
auto test = node::ObjectWrap::Unwrap<Test>(args.Holder());
int nCount = test->number;
std::cout << "JSCalc, Wait..." <<nCount <<"s" << std::endl;
auto jsCallback = v8::Local<v8::Function>::Cast(args[0]);
Data* pData = new Data;
pData->callback.Reset(args.GetIsolate(), jsCallback);
pData->count = nCount;
uv_work_t* work = new uv_work_t;
work->data = pData;
uv_queue_work(uv_default_loop(), work, (uv_work_cb)calculate, (uv_after_work_cb)complete);
}
static v8::Persistent<v8::Function> constructor;
private:
int number = 0;
};
void Init(v8::Local<v8::Object> exports)
{
Test::Init(exports);
}
NODE_MODULE(NODE_MODULE_NAME_YPP, Init);
};
JS調用代碼:
const addon = require('./bin/invoke');
const obj1 = new addon.Test;
obj1.SetNumber(9);
obj1.Calc((sum)=>{
console.log('total:' + sum);
});
異步調用JSCalc中用到了NodeJs模塊中的yuv模塊,將calc放在了額外的模塊中執行。這個異步操作不可用其他thread代替,否則NodeJs不會等待回調,主線程邏輯完成後直接會退出進程。
附上完全demo:https://download.csdn.net/download/linfengmove/11778028