我想构建一个电子应用程序,可以访问大化的数字视频录制(DVR)产品。我使用node-ffi访问大华提供的dhnetsdk.dll,可以调用CLIENT_Init方法初始化SDK,但无法调用CLIENT_LoginEx2方法登录DVR设备。
问题可能是C ++指针,但我不确定。代码如下所示。
CLIENT_NET_API LLONG CALL_METHOD CLIENT_LoginEx2(
const char *pchDVRIP,
WORD wDVRPort,
const char *pchUserName,
const char *pchPassword,
EM_LOGIN_SPAC_CAP_TYPE emSpecCap,
void* pCapParam,
LPNET_DEVICEINFO_Ex lpDeviceInfo,
int *error = 0
);
const DVR = ffi.Library('dhnetsdk.dll', {
// SDK
CLIENT_Init: [ref.types.bool, ['pointer', ref.types.int64]],
CLIENT_GetSDKVersion: [ref.types.uint, []],
// Login
CLIENT_LoginEx2: [
ref.types.int64, [
ref.types.char,
ref.types.ushort,
ref.types.char,
ref.types.char,
ref.types.int,
'void *',
ref.refType(NET_DEVICEINFO_Ex),
ref.types.int
]
],
});
index.ts
const NET_DEVICEINFO_Ex = StructType({
'sSerialNumber': ArrayType(ref.types.byte, DH_DEV_SERIALNO_LEN),
'nAlarmInPortNum': ref.types.int,
'nAlarmOutPortNum': ref.types.int,
'nDiskNum': ref.types.int,
'nDVRType': ref.types.int,
'nChanNum': ref.types.int,
'byLimitLoginTime': ref.types.byte,
'byLeftLogTimes': ref.types.byte,
'bReserved': ArrayType(ref.types.byte, 2),
'nLockLeftTime': ref.types.int,
'Reserved': ArrayType(ref.types.char, 24),
});
dhnetsdk.h
typedef struct
{
BYTE sSerialNumber[DH_SERIALNO_LEN];
int nAlarmInPortNum;
int nAlarmOutPortNum;
int nDiskNum;
int nDVRType;
int nChanNum;
BYTE byLimitLoginTime;
BYTE byLeftLogTimes;
BYTE bReserved[2];
int nLockLeftTime;
char Reserved[24];
} NET_DEVICEINFO_Ex, *LPNET_DEVICEINFO_Ex;
let lpDeviceInfo = ref.alloc(NET_DEVICEINFO_Ex);
let error = 0;
console.log(DVR.CLIENT_Init(disConnectCallback, 0));
console.log(DVR.CLIENT_LoginEx2('192.168.1.100', 37777, 'admin', 'dh123456', 0, null, lpDeviceInfo, error));
console.log(DVR.CLIENT_GetSDKVersion());
当我运行代码时,DVR.CLIENT_Init和DVR.CLIENT_GetSDKVersion的结果如下图所示返回,我可以确认sdk正常工作。
当我调用DVR.CLIENT_LoginEx2时,Electron应用程序崩溃并返回了以下屏幕截图。
DevTools已从页面断开连接。页面重新加载后, DevTools将自动重新连接。
我认为这可能是由错误的数据结构定义引起的,但是我真的不知道如何跟踪错误的地方。请提供建议,非常感谢。
5月3日更新
SDK手册编写了一个片段,以演示如何按以下方式调用CLIENT_LoginEx2
LLONG lLoginHandle = CLIENT_LoginEx2(szDevIp, nPort, szUserName, szPasswd,
EM_LOGIN_SPEC_CAP_TCP, NULL, &stDevInfo, &nError);
它显示了最后两个参数需要传递指针,参数&stDevInfo是指向NET_DEVICEINFO_Ex数据结构的结构的指针,参数&nError是从方法回调返回错误代码的指针。
我想这可能是崩溃的原因,但不确定,任何人都可以帮助我弄清楚是什么问题,谢谢。
5月3日更新
经过一些努力它可能会起作用,我将ffi.Library重新定义如下 关键是需要通过ref.refType('char')或简称为'string'传递的'char *';简而言之,需要通过ref.refType('void')或'pointer'传递'void *'; 需要通过ref.refType('int')或简称为'int *'传递。
const NetDeviceInfoEx = StructType({
'sSerialNumber': ArrayType(ref.types.byte, DH_DEV_SERIALNO_LEN),
'nAlarmInPortNum': ref.types.int,
'nAlarmOutPortNum': ref.types.int,
'nDiskNum': ref.types.int,
'nDVRType': ref.types.int,
'nChanNum': ref.types.int,
'byLimitLoginTime': ref.types.byte,
'byLeftLogTimes': ref.types.byte,
'bReserved': ArrayType(ref.types.byte, 2),
'nLockLeftTime': ref.types.int,
'Reserved': ArrayType(ref.types.char, 24),
});
const NetDeviceInfoExPtr = ref.refType(NetDeviceInfoEx);
CLIENT_LoginEx2: [
ref.types.int64, [
'string',
ref.types.ushort,
'string',
'string',
ref.types.int,
'pointer',
NetDeviceInfoExPtr, // or ref.refType('NetDeviceInfoEx')
'int*'
]
],
以下代码实际上称为DLL 请注意,我们需要定义输出参数变量以从返回的DLL中获取消息。
// Output Parameters
var lpDeviceInfo = ref.alloc(NetDeviceInfoEx);
var error = ref.alloc('int');
var v = DVR.CLIENT_LoginEx2('192.168.1.100', 37777, 'admin', 'dh123456', EM_LOGIN_SPAC_CAP_TYPE.EM_LOGIN_SPEC_CAP_TCP.value, null, lpDeviceInfo, error);
console.log(v);
console.log(lpDeviceInfo.deref());
因为我没有DVR设备来测试代码,所以无法确认它是否有效。明天进入办公室后,我会对其进行测试。
答案 0 :(得分:0)
我的问题帖子中的最新更新是,我找出了定义ffi.Library的正确方法。
我由于对C语言的误解而犯错。关键是需要通过ref.refType('char')或简称为'string'传递的'char *';简而言之,需要通过ref.refType('void')或'pointer'传递'void *'; 需要通过ref.refType('int')或简称为'int *'传递。
所以我重写了下面的代码,终于可以了。
const NetDeviceInfoEx = StructType({
'sSerialNumber': ArrayType(ref.types.byte, DH_DEV_SERIALNO_LEN),
'nAlarmInPortNum': ref.types.int,
'nAlarmOutPortNum': ref.types.int,
'nDiskNum': ref.types.int,
'nDVRType': ref.types.int,
'nChanNum': ref.types.int,
'byLimitLoginTime': ref.types.byte,
'byLeftLogTimes': ref.types.byte,
'bReserved': ArrayType(ref.types.byte, 2),
'nLockLeftTime': ref.types.int,
'Reserved': ArrayType(ref.types.char, 24),
});
const NetDeviceInfoExPtr = ref.refType(NetDeviceInfoEx);
/**
* LLONG CLIENT_LoginEx2(
* const char *pchDVRIP,
* WORD wDVRPort,
* const char *pchUserName,
* const char *pchPassword,
* EM_LOGIN_SPAC_CAP_TYPE emSpecCap,
* void* pCapParam,
* LPNET_DEVICEINFO_Ex lpDeviceInfo,
* int *error
* );
*/
CLIENT_LoginEx2: [ref.types.int64, ['string', ref.types.ushort, 'string', 'string', ref.types.int, 'pointer', NetDeviceInfoExPtr, 'int*']],
以下代码实际上调用了DLL。请注意,我们需要定义输出参数变量以从返回的DLL中获取消息。
// Output Parameters
var lpDeviceInfo = ref.alloc(NetDeviceInfoEx);
var error = ref.alloc('int');
var v = DVR.CLIENT_LoginEx2('192.168.1.100', 37777, 'admin', 'dh123456', EM_LOGIN_SPAC_CAP_TYPE.EM_LOGIN_SPEC_CAP_TCP.value, null, lpDeviceInfo, error);
console.log(v); // it will return device ID by DLL defined
console.log(lpDeviceInfo.deref()); // it will return NetDeviceInfoEx struct data