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"]]
});
运行不正常。哪里不正确呢
看不懂问题… 先给楼主格式化一遍代码…
[@jiyinyiyong](/user/jiyinyiyong) 已经格式化了,请指点一下,谢谢了
node.js哪能直接调用c代码呢?得编写一个 addon。
该问题已经被解决,结构体直接使用node-struct模块,如果还是不好用,那么就直接申请一块连续的内存来处理! nodejs调用c接口的dll,如果有回调的接口,该进程一定要阻塞住不要退出,但是不要使用while死循环来阻塞。
最近也遇到这个问题,方便把解决代码贴下么,谢谢
[@lvhy](/user/lvhy) 你可以加入这个群QQ 397941452
要正确调用 NP_GB_Login
函数,你需要确保以下几点:
- 结构体定义:确保结构体定义与 C 语言中的定义一致。
- 回调函数:确保回调函数的定义正确。
- 函数签名:确保函数签名与 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();
关键点解释:
- 结构体定义:使用
char[16]
和char[24]
等来表示固定长度的字符数组。 - 回调函数:使用
ffi.Callback
来定义回调函数,并确保其签名与 C 语言中的定义一致。 - 函数签名:确保函数签名与 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();
注意以下几点:
- 结构体中的每个字段都应与C语言中的定义一致。
- 回调函数的定义要正确。
- 确保DLL路径正确,并且DLL已加载到系统中。
希望这能帮助你解决问题!