关于ffi-napi结合ref-napi调用dll的经验总结

在具体的electron项目中,需要调用本地c++编写的dll函数,函数中国有多个out parameter,但是各种尝试,发现最新的如下版本不支持引用传递

"dependencies": {
	"ffi-napi": "^2.5.0",
 	"ref-napi":"^2.0.3"
 }

"devDependencies": {
    "@types/ffi-napi": "^3.0.1",
    "@types/ref-napi":"^3.0.1"
}

尽管node-ffi文档Node FFI Tutorial写了可以支持的,不知道是不是ref-napi和node-ffi有什么差异,导致的,反正我这里就是不支持的,尝试使用如下node-ffi依赖(node-ffi不支持node10以上版本)

 "ffi": "github:lxe/node-ffi#node-12",
 "ref": "github:lxe/ref#node-12"

但是无论使用npm还是yarn都无法正常的install,另外我的项目是基于typescript的这两个依赖看起来也没有对应的@types依赖,故放弃。

最后无赖还是采用Node FFI Tutorial文档中的回调函数来解决多参数返回的问题,c++代码如下
myhello.h

#pragma once
#ifndef TestDll_H_
#define TestDll_H_
#ifdef MYLIBDLL
#define MYLIBDLL extern "C" _declspec(dllimport)
#else
#define MYLIBDLL extern "C" _declspec(dllexport)
#endif
MYLIBDLL char* Hello();
MYLIBDLL float Add(float plus1, float plus2);
MYLIBDLL int StrLength(char * str);
MYLIBDLL void changeStr(char* str);
MYLIBDLL void changeNum(int* num);
MYLIBDLL void setCallBack(void (*)(int, char* str));
#endif

myhello.cpp

#include "myhello.h"
#include<stdlib.h>
#include <iostream>
using namespace std;
float Add(float plus1, float plus2)
{
	float add_result = plus1 + plus2;
	return add_result;
}

char* Hello()
{
	return "Hello This is Cpp Addon";
}

int StrLength(char* str)
{
	return strlen(str);
}

char* outStr = "hello world";
void changeStr(char* str) {
	char src[] = "xiaojiayu";
	strcpy(str, src);
}

int outNumber = 10;
void changeNum(int* num) {
	num = &outNumber;
}

void setCallBack(void (*func)(int, char* str)) {
	func(12, "yjing");
}

编译出来的dll为myhello.dll,对应的通过如下ts代码调用myhello.dll

var myHelloLib = ffi.Library('../../dll/myhello.dll', {
      'Hello': ['string', ['string']],
      'StrLength': ['int', ['string']],
      'init': ['int*', []],
      'get': ['int', ['int*']],
      'release': ['void', ['int*']],
      'selectball': ['void', ['pointer']]
    })
    const buffer = new Buffer(20);
    buffer.writeCString('wo shi da ying', 0);
    var retBuffer = myHelloLib.Hello(buffer);
    console.log('after call Hello buffer' + ref.readCString(buffer, 0));
    console.log('this is Hello ' + myHelloLib.Hello(buffer));

    var idx = myHelloLib.init()
    console.log("I get id")
    console.log(myHelloLib.get(idx))
    console.log('realse ' + myHelloLib.release(idx))

    console.log('StrLength = ' + myHelloLib.StrLength(retBuffer));


    var callback = ffi.Callback('void', ['int', 'string'],
      function (id, name) {
        console.log("id: ", id);
        console.log("name: ", name);
      });
    myHelloLib.selectball(callback);

console输出结果如下

D:\study\electron\electron-quick-start\preload.js:25 myHelloLib add = 7
D:\study\electron\electron-quick-start\preload.js:29 myHelloLib Hello = Hello This is Cpp Addon
D:\study\electron\electron-quick-start\preload.js:31 id: 12name: yjing
D:\study\electron\electron-quick-start\preload.js:37 actrualStr = xiaojiayu
D:\study\electron\electron-quick-start\preload.js:41 actualNum = 0
D:\study\electron\electron-quick-start\preload.js:27 aync res = 11

注意这里的name只是暑促了y,应为c++回调的字符串包含了特殊字符’\0’表示该字符串结束的位置,这点应该特别注意下。另外需要注意的是ffi-napi本身是支持应用传递的,如例子所示,但是一定要注意
native端要使用类似strcpy的函数来给传入的参数赋值,这个可以参考这篇文章,how to get value of ''c #397


版权声明:本文为Yoryky原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。