首页 > 解决方案 > 如何使用 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 没有记录,我相信我不成功的调用会扰乱流程。

尝试了以下方法:

我对 c++ 的理解有限,可能遗漏了一些关于类型和指针的部分,但这看起来很简单,应该不会出错......

平台:windows 10, 64 bit, node v14.12.0, VS 2019 Community

版本:“ffi-napi”:“^4.0.3”,“ref-napi”:“^3.0.2”

感谢您的输入 :-)

标签: c++node.jsnode-modulesffi

解决方案


在查看@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!

如果有人知道更简单的方法或这样做(而不是发送字符串?),那就太好了。


推荐阅读