c++ - 如何使用 node 和 ffi-napi 从 c++ dll 接收字符串?
问题描述
我正在尝试做一个简单的概念证明,并使用 ffi-napi 从节点调用一个非常基本的 c++ dll。
当我使用获取/返回 int 或 char 的方法时,它工作正常,但我返回字符串的尝试失败了。
c++代码,main.h:
#include <string>
#include <stdlib.h>
using namespace std;
#define EXPORT __declspec(dllexport)
extern "C" {
EXPORT string hello(string x);
EXPORT int count(int x);
}
c++代码,main.cpp:
#include "pch.h"
#include <string>
#include <stdlib.h>
#include "Main.h"
using namespace std;
string hello(string name)
{
return "Hello " + name + "! ";
}
int count(int x)
{
return x+1;
}
当我在下面运行节点代码时,
import { Console } from "node:console";
var ffi = require('ffi-napi');
var ref = require('ref-napi');
export class DllTester {
LibName: string = 'D:\\temp\\DemoDll\\x64\\Debug\\DemoDll.dll';
Lib: any = null;
private setupOcrLib()
{
this.Lib = ffi.Library(this.LibName,
{'hello': [ 'string', ['string']],
'count': [ ref.types.int, [ref.types.int]]
}
);
}
count(x: number): number {
this.setupOcrLib();
console.log("Calling count");
return this.Lib.count(x);
}
hello(name: string): string {
this.setupOcrLib();
console.log("Calling hello: " + name);
return this.Lib.hello(name);
}
}
const tester = new DllTester();
console.log("Count: " + tester.count(3));
console.log("Hello: " + tester.hello("Markus"));
console.log("Count: " + tester.count(10));
我得到以下控制台输出:
Calling count
Count: 4
Calling hello: Markus
所以第一次调用(发送 int,接收 int)工作正常,但第二次调用(发送字符串,接收字符串)静默失败,并且由于第二次调用 count 没有记录,我相信我不成功的调用会扰乱流程。
尝试了以下方法:
- 在 dll 中使用 char* 而不是字符串。然后我收到“东西”但不可读的文本
- 使用 ref-napi 设置类型而不是字符串,但演示表明这不是必需的:https ://github.com/node-ffi-napi/node-ffi-napi
我对 c++ 的理解有限,可能遗漏了一些关于类型和指针的部分,但这看起来很简单,应该不会出错......
平台:windows 10, 64 bit, node v14.12.0, VS 2019 Community
版本:“ffi-napi”:“^4.0.3”,“ref-napi”:“^3.0.2”
感谢您的输入 :-)
解决方案
在查看@PaulMcKenzies 答案后让它工作:我不是简单地使用字符串,而是创建一个缓冲区并使用指针。
C++ 代码,main.h:
#include <string>
#include <stdlib.h>
using namespace std;
#define EXPORT __declspec(dllexport)
extern "C" {
EXPORT void helloPtr(char* x);
EXPORT int count(int x);
}
c++代码,main.cpp:
#include "pch.h"
#include <string>
#include <stdlib.h>
#include "Main.h"
using namespace std;
void helloPtr(char* name)
{
std::string names(name);
std::string results = "Hello " + names + "!";
strcpy_s(name, 200, results.c_str());
}
int count(int x)
{
return x+1;
}
节点:
import { Console } from "node:console";
var ffi = require('ffi-napi');
var ref = require('ref-napi');
export class DllTester {
LibName: string = 'D:\\temp\\DemoDll\\x64\\Debug\\DemoDll.dll';
Lib: any = null;
constructor() {
this.setupLib();
}
private setupLib()
{
this.Lib = ffi.Library(this.LibName,
{'helloPtr': [ ref.types.void, ['char *']],
'count': [ ref.types.int, [ref.types.int]]
}
);
}
count(x: number): number {
return this.Lib.count(x);
}
helloPtr(name: string): string {
//setup buffer
var maxLength = 200;
var nameBuffer = Buffer.alloc(maxLength);
nameBuffer.fill(0);
nameBuffer.write(name, 0, "utf-8");
this.Lib.helloPtr(nameBuffer);
//get result from buffer
var helloResult = nameBuffer.toString('utf-8');
var terminatingNullPos = helloResult.indexOf('\u0000');
if (terminatingNullPos >= 0) {
helloResult = helloResult.substr(0, terminatingNullPos);
}
return helloResult;
}
}
const tester = new DllTester();
console.log(tester.helloPtr("Markus"));
这会将所需的消息打印到控制台中:Hello Markus!
如果有人知道更简单的方法或这样做(而不是发送字符串?),那就太好了。
推荐阅读
- swift - 试图从 3 个组件 pickerView 中获取 3 个单独的整数
- python - Django - 在 Serializer 中将 2 个属性压缩在一起
- r - 如何合并ggpplot中的图例
- vue.js - Antd与元素UI风格冲突
- python - 导入nltk包时如何解决以下错误
- javascript - 单击不同按钮时如何淡入相同的DIV?
- java - 意外的 AST 节点:Spring Data Jpa 中的 {vector}
- python - 以 base64 字符串形式读取 pandas 列
- node.js - html-pdf 在 docker 中无法创建 pdf
- java - 具有自定义用户名和密码查询的 Spring Security JDBC 身份验证