NodeJS调用Dll模块

本文介绍了NodeJS如何调用DLL模块,包括注册入口函数、初始化接口以及给JavaScript提供可调用的方法和类对象。通过示例展示了C++函数接口的形式,并给出了JavaScript调用这些接口的具体代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

参考: 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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值