最近研究在Nodejs中调用DLL,上网搜索发现主要有两种方法:
- 使用Nodeffi调用C风格接口的DLL,但是无法调用C++风格导出类的DLL。
- 使用Nodejs C++ Addon 插件,该方法可直接与C++代码交互,理论上可以调用C++风格导出类的DLL。
下面研究Nodejs Addon C++插件的编写方法。
什么是Nodejs C++ Addon
Node.js插件(Addons)是C/C++编写的动态链接对象,这些对象可以被Node.js的require()函数引用,并可以像普通的Node.js模块一样使用。Addons主要用于提供一个Node.js中运行的JavaScript和C/C++库之间的接口。
插件(Addons)是动态链接的共享对象,它提供了C/C++类库的调用能力。实现插件的方法比较复杂,涉及到以下元组件及API:
- V8:C++库,Node.js用于提供JavaScript执行环境。V8提供了对象创建、函数调用等执行机制,V8相关API包含在了v8.h头文件中(位于Node.js源码树的deps/v8/include/v8.h),也可以查看在线文档。
- libuv:C库,实现了Node.js中的事件循环、工作线程及在不同平台中异步行为的相关功能。也可以做为是一个跨平台的抽象库,提供了简单的、类POSIX的对主要操作系统的常见系统任务功能,如:与文件系统、套接字、计时器、系统事件的交互等。libuv还提供了一个类pthreads的线程池抽象对象,可用于更复杂的、超越标准事件循环的异步插件的控制功能。
- 内部Node.js库:Node.js自身提供了一定义数量的C/C++API的插件可以使用 - 其中最重要的可能是node::ObjectWrap类
- Node.js静态链接库:Node.js自身还包含了一部分静态链接库,如OpenSSL。这些位于Node.js源码树的deps/目录下,只有V8和OpenSSL提供了符号出口,可以供Node.js和基它插件所使用。详见Node.js依赖链接
Node Addon插件编写方法
Node Addon插件的编写需要解决两个关键问题:
- 当数据流向 javaScript -> C++时,如何将javascript类型数据包装成C++类型数据,供C++代码使用。
- 当数据流向 C++ -> JavaScript时,如何将C++类型数据包装成JavaScript类型数据,供JavaScript代码使用。
这两个关键问题的分析请参见淘宝前端团队成员发表的文章“Node.js 和 C++ 之间的类型转换[3]”。解决这两个关键问题后,Node Addon插件编写难度就不大了。
Node Addon插件调用C++导出类DLL方法测试
现有一个采用成熟方法导出类接口的DLL[4],如何在Node Addon插件中调用该DLL呢?下面nodejs官网Node Addon插件例子Factory of wrapped objects为例进行讲解。
Factory of wrapped objects例子在Addon插件中包装了一个MyObject类,现在就在MyObject类调用DLL导出类的接口方法。修改MyObject.h代码,增加DLL导出类接口方法,增加类接口成员变量IExport和DLL句柄变量hDll,如下所示:
1 | // myobject.h |
接下来将在MyObject类的构造函数中动态加载DLL,创建DLL导出类对象,在析构函数中析构DLL导出类对象,动态卸载DLL,在MyObject成员方法中调用DLL导出类方法,代码如下所示:
1 | // myobject.cc |
参考链接
- Node.js C/C++插件(Addons), by IT笔录
- Node.js v8.16.1 Documentation,by nodejs
- type-casts-between-node-and-cpp,by 淘宝前端团队
- DLL导出类和函数,by jackhuang