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),我们可以使用ffi
和ref
等库。根据你提供的头文件和代码片段,我们来解决几个问题:
- 结构体定义:你的结构体定义需要与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 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);
解释:
- 结构体定义:我们需要定义字符串类型为固定长度,例如
string16
、string24
和string64
。这确保了结构体的大小与C语言中的定义一致。 - 回调函数:我们使用
ffi.Callback
来定义回调函数,并确保其签名与C语言中的签名一致。 - 加载库:使用
ffi.Library
加载DLL或SO文件,并指定函数的签名。 - 初始化和调用:初始化SDK,创建
LogInfo
实例并填充数据,然后调用NP_GB_Login
函数。
通过这些步骤,你可以正确地调用C语言编写的DLL或SO文件中的函数。
要正确地调用 NP_GB_Login
函数,需要注意几个关键点:
- 结构体定义:结构体字段需要与 C 结构体中的数据类型相匹配。
- 回调函数定义:确保使用正确的 FFI 回调函数定义。
- 指针类型:正确处理指针类型。
以下是修正后的代码示例:
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);
解释:
- 结构体定义:确保每个字段的类型与 C 结构体中的一致,并使用
ref.allocCString
分配字符串。 - 回调函数:使用
ffi.Callback
定义回调函数。 - 库加载:通过
ffi.Library
加载库,并定义函数签名。 - 初始化:调用
NP_GB_Init
进行初始化。 - 调用函数:创建结构体实例并传递给
NP_GB_Login
函数。
这样应该可以解决你的问题。如果还有其他问题,请检查是否正确加载了 .dll
文件以及路径是否正确。