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"]]
});

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


8 回复

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


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

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

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

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

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

要使用Node.js调用C语言编写的动态链接库(DLL或SO),我们可以使用ffiref等库。根据你提供的头文件和代码片段,我们来解决几个问题:

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

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

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 string16 = 'string16';
var string24 = 'string24';
var string64 = 'string64';

// 结构体定义
var LogInfo = Struct({
  'severip': string16,
  'severport': int32_t,
  'severid': string24,
  'localip': string16,
  'localport': int32_t,
  'username': string24,
  'password': string64,
  'keepalive': int32_t,
  'timeout': int32_t,
  'expires': int32_t
});

// 回调函数定义
var Callback_Offline = ffi.Callback('void', ['pointer'], function(userdata) {
  console.log('Offline callback triggered');
});

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

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

// 创建LogInfo实例
var logInfo = new LogInfo();
logInfo.severip = '192.168.1.1'; // 示例IP地址
logInfo.severport = 5000;
logInfo.severid = 'server01';
logInfo.localip = '192.168.1.2';
logInfo.localport = 6000;
logInfo.username = 'admin';
logInfo.password = 'password123';
logInfo.keepalive = 60;
logInfo.timeout = 30;
logInfo.expires = 120;

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

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

解释:

  1. 结构体定义:我们需要定义字符串类型为固定长度,例如string16string24string64。这确保了结构体的大小与C语言中的定义一致。
  2. 回调函数:我们使用ffi.Callback来定义回调函数,并确保其签名与C语言中的签名一致。
  3. 加载库:使用ffi.Library加载DLL或SO文件,并指定函数的签名。
  4. 初始化和调用:初始化SDK,创建LogInfo实例并填充数据,然后调用NP_GB_Login函数。

通过这些步骤,你可以正确地调用C语言编写的DLL或SO文件中的函数。

要正确地调用 NP_GB_Login 函数,需要注意几个关键点:

  1. 结构体定义:结构体字段需要与 C 结构体中的数据类型相匹配。
  2. 回调函数定义:确保使用正确的 FFI 回调函数定义。
  3. 指针类型:正确处理指针类型。

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

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

// 定义基本类型
var voidptr = ref.refType(ref.types.void);
var int32_t = ref.types.int32;
var string_ptr = ref.refType(ref.types.char);

// 定义结构体
var LogInfo = Struct({
  'severip': string_ptr,
  'severport': int32_t,
  'severid': string_ptr,
  'localip': string_ptr,
  'localport': int32_t,
  'username': string_ptr,
  'password': string_ptr,
  'keepalive': int32_t,
  'timeout': int32_t,
  'expires': int32_t
});

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

// 加载库
var SDKHandle = ffi.Library('./sdk.dll', {
  'NP_GB_Init': ['void', []],
  'NP_GB_Cleanup': ['void', []],
  'NP_GB_Login': ['int', ['void*', LogInfo, voidptr]],
  'NP_GB_Logout': ['void', []]
});

// 初始化
SDKHandle.NP_GB_Init();

// 创建结构体实例
var logInfo = new LogInfo({
  severip: ref.allocCString('192.168.1.1'),
  severport: 5060,
  severid: ref.allocCString('server_id'),
  localip: ref.allocCString('192.168.1.2'),
  localport: 5061,
  username: ref.allocCString('user'),
  password: ref.allocCString('pass'),
  keepalive: 60,
  timeout: 30,
  expires: 120
});

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

解释:

  1. 结构体定义:确保每个字段的类型与 C 结构体中的一致,并使用 ref.allocCString 分配字符串。
  2. 回调函数:使用 ffi.Callback 定义回调函数。
  3. 库加载:通过 ffi.Library 加载库,并定义函数签名。
  4. 初始化:调用 NP_GB_Init 进行初始化。
  5. 调用函数:创建结构体实例并传递给 NP_GB_Login 函数。

这样应该可以解决你的问题。如果还有其他问题,请检查是否正确加载了 .dll 文件以及路径是否正确。

回到顶部