Nodejs 涉及dll/so调用,结构体参数类型如何定义,函数如何调用呢

Nodejs 涉及dll/so调用,结构体参数类型如何定义,函数如何调用呢

这是部分 .h 头文件

#ifndef _GENERIC_GB_API_H_
#define _GENERIC_GB_API_H_

#ifdef WIN32
#ifdef DLL_GBSDK
#define GBAPI _declspec(dllexport)
#else
#define GBAPI _declspec(dllimport)
#endif
#else
#define GBAPI
#endif

typedef unsigned long long UINT64;
typedef long long INT64;

#ifdef __cplusplus 
extern "C" { 
#endif 

typedef struct _LogInfo
{
	char severip[16]; //内存占16个字节
	int  severport;
    char severid[24];
    char localip[16];
    int  localport;
	char username[24];
	char password[64];
    int  keepalive;
	int  timeout;
	int  expires;
}LogInfo;

typedef void (*Callback_Offline)( void *userdata );

void GBAPI NP_GB_Init();

int GBAPI NP_GB_Login( void* userdata, LogInfo &info, Callback_Offline callback );

int GBAPI NP_GB_OpenToDecoder( char* id, char* decoder );
#ifdef __cplusplus 
}  
#endif
#endif

我想问的是如何调 NP_GB_Login 函数呢?写了一部分代码,下面不知道该如何写了,这个结构体定义正确吗?

var ffi = require('ffi');
var ref = require('ref');
var Struct = require('ref-struct');
//var hWnd = new Buffer(8);
var int64_t = ref.types.int64;
var voidptr = ref.refType(ref.types.void);
var intptr = ref.refType(ref.types.int);
var uint8_ptr = ref.refType(ref.types.uint8);
/** 登录信息
 *
 */
var _LogInfo = Struct({
  'severip': "string",
  'severport': "int32",
  "severid": "string",
  "localip": "string",
  "localport": "int32",
  "username": "string",
  "password": "string",
  "keepalive": "int32",
  "timeout": "int32",
  "expires": "int32"
});
//byte[24];
var _LogInfoPtr = ref.refType(_LogInfo);
var Callback_Offline=ffi.callback("void",["void"],function(userdata){

});
var SDKHandle = ffi.Library('./sdk.dll', {
  'NP_GB_Init': ['void', ["void"]],
  'NP_GB_Cleanup': ['void', ["void"]],
  'NP_GB_Login': ['int', ["void",_LogInfoPtr,"pointer"]],
  'NP_GB_Logout': ['void', ["void"]]
});

运行不正常。哪里不正确呢


9 回复

看不懂问题… 先给楼主格式化一遍代码…


[@jiyinyiyong](/user/jiyinyiyong) 已经格式化了,请指点一下,谢谢了

node.js哪能直接调用c代码呢?得编写一个 addon

该问题已经被解决,结构体直接使用node-struct模块,如果还是不好用,那么就直接申请一块连续的内存来处理! nodejs调用c接口的dll,如果有回调的接口,该进程一定要阻塞住不要退出,但是不要使用while死循环来阻塞。

最近也遇到这个问题,方便把解决代码贴下么,谢谢

[@lvhy](/user/lvhy) 你可以加入这个群QQ 397941452

要正确调用 NP_GB_Login 函数,你需要确保以下几点:

  1. 结构体定义:确保结构体定义与 C 语言中的定义一致。
  2. 回调函数:确保回调函数的定义正确。
  3. 函数签名:确保函数签名与 C 语言中的定义一致。

以下是修正后的代码示例:

var ffi = require('ffi');
var ref = require('ref');
var Struct = require('ref-struct');

// 定义基本类型
var int32_t = ref.types.int32;
var int64_t = ref.types.int64;
var uint8_t = ref.types.uint8;
var voidptr = ref.refType(ref.types.void);

// 定义结构体
var _LogInfo = new Struct({
  'severip': 'char[16]', // 字符数组
  'severport': int32_t,
  'severid': 'char[24]',
  'localip': 'char[16]',
  'localport': int32_t,
  'username': 'char[24]',
  'password': 'char[64]',
  'keepalive': int32_t,
  'timeout': int32_t,
  'expires': int32_t
});

// 定义回调函数
var Callback_Offline = ffi.Callback('void', [voidptr], function(userdata) {
  console.log('Offline callback called with user data:', userdata);
});

// 加载动态库
var SDKHandle = ffi.Library('./sdk.dll', {
  'NP_GB_Init': ['void', []],
  'NP_GB_Cleanup': ['void', []],
  'NP_GB_Login': ['int', [_LogInfo, voidptr]], // 修改为正确的函数签名
  'NP_GB_Logout': ['void', []]
});

// 初始化
SDKHandle.NP_GB_Init();

// 示例登录信息
var loginInfo = new _LogInfo({
  'severip': '192.168.1.1',
  'severport': 5000,
  'severid': 'server1',
  'localip': '192.168.1.2',
  'localport': 6000,
  'username': 'admin',
  'password': 'password',
  'keepalive': 60,
  'timeout': 30,
  'expires': 120
});

// 调用登录函数
var result = SDKHandle.NP_GB_Login(loginInfo, Callback_Offline);
console.log('Login result:', result);

// 清理
SDKHandle.NP_GB_Cleanup();

关键点解释:

  1. 结构体定义:使用 char[16]char[24] 等来表示固定长度的字符数组。
  2. 回调函数:使用 ffi.Callback 来定义回调函数,并确保其签名与 C 语言中的定义一致。
  3. 函数签名:确保函数签名与 C 语言中的定义一致。例如,NP_GB_Login 的签名应该是 ['int', [_LogInfo, voidptr]]

通过以上修改,你应该能够正确调用 NP_GB_Login 函数。

你的_LogInfo结构体定义中字符串类型使用了"string",但更准确的定义应该使用"char *"或固定长度的字符数组。另外,在NP_GB_Login函数声明中,第二个参数应该是指向LogInfo结构体的指针。

以下是修正后的代码:

var ffi = require('ffi');
var ref = require('ref');
var Struct = require('ref-struct');

var int32_t = ref.types.int;
var int64_t = ref.types.int64;
var uint64_t = ref.types.uint64;
var voidptr = ref.refType(ref.types.void);

var _LogInfo = Struct({
  'severip': 'char [16]',
  'severport': int32_t,
  'severid': 'char [24]',
  'localip': 'char [16]',
  'localport': int32_t,
  'username': 'char [24]',
  'password': 'char [64]',
  'keepalive': int32_t,
  'timeout': int32_t,
  'expires': int32_t
});

var Callback_Offline = ffi.Callback('void', ['void *'], function (userdata) {});

var SDKHandle = ffi.Library('./sdk.dll', {
  'NP_GB_Init': ['void', []],
  'NP_GB_Login': ['int', ['void *', _LogInfo, Callback_Offline]]
});

确保你传递给NP_GB_Login的参数类型正确,并且Callback_Offline函数也正确地被定义为回调。

你的代码基本上是正确的,但有一些小细节需要调整。首先,确保你的结构体定义与C语言中的定义一致,特别是字符串长度。其次,ffi库中的回调函数类型也需要正确设置。

以下是修正后的代码:

var ffi = require('ffi');
var ref = require('ref');
var Struct = require('ref-struct');

// 定义基本类型
var int64_t = ref.types.int64;
var voidptr = ref.refType(ref.types.void);
var uint8_t = ref.types.uint8;

// 定义结构体
var _LogInfo = Struct({
  'severip': 'char[16]',
  'severport': 'int',
  'severid': 'char[24]',
  'localip': 'char[16]',
  'localport': 'int',
  'username': 'char[24]',
  'password': 'char[64]',
  'keepalive': 'int',
  'timeout': 'int',
  'expires': 'int'
});

// 定义回调函数类型
var Callback_Offline = ffi.Callback('void', [voidptr], function (userdata) {
  console.log('Offline callback called with:', userdata);
});

// 加载DLL并定义函数
var SDKHandle = ffi.Library('./sdk.dll', {
  'NP_GB_Init': ['void', []],
  'NP_GB_Cleanup': ['void', []],
  'NP_GB_Login': ['int', ['pointer', _LogInfo, voidptr]],
  'NP_GB_Logout': ['void', []]
});

// 初始化SDK
SDKHandle.NP_GB_Init();

// 创建一个实例化的结构体
var logInfo = new _LogInfo();
logInfo.severip = '192.168.1.1';
logInfo.severport = 12345;
logInfo.severid = 'server1';
logInfo.localip = '192.168.1.2';
logInfo.localport = 54321;
logInfo.username = 'user';
logInfo.password = 'pass';
logInfo.keepalive = 60;
logInfo.timeout = 30;
logInfo.expires = 120;

// 调用登录函数
var result = SDKHandle.NP_GB_Login(null, logInfo, Callback_Offline);

console.log('Login result:', result);

// 清理SDK
SDKHandle.NP_GB_Cleanup();

注意以下几点:

  1. 结构体中的每个字段都应与C语言中的定义一致。
  2. 回调函数的定义要正确。
  3. 确保DLL路径正确,并且DLL已加载到系统中。

希望这能帮助你解决问题!

回到顶部