我想构建一个可以从Dahua访问数字视频录制(DVR(产品的电子应用程序。我使用node-ffi访问dhnetsdk.dll从dahua提供的dhnetsdk.dll,可以调用client_init方法来初始化sdk,但是我无法调用client_loginex2方法登录DVR设备。
问题可能是C 指针,但我不确定。代码在下面显示。
- client_loginex2 dhnetsdk.h 中定义的方法
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
);
- index.ts中的client_loginex2方法(由node-ffi(
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中定义net_deviceinfo_ex数据结构(dhnetsdk.dll的结构参考(
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工作。
屏幕截图1
当我致电DVR.CLIENT_LOGINEX2时,电子应用崩溃并如下屏幕截图返回。
DevTools与页面断开。一旦页面重新加载, DevTools将自动重新连接。
屏幕截图2
我认为这可能会导致错误的数据结构定义,但我真的不知道如何跟踪错误的位置。请给出建议,真的很感激。
更新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'(或"字符串"简单地传递的" char*"需求;简而言之,Ref.Reftype('void'(或"指针"传递了" void*"的需求;'int*'需要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设备来测试代码,所以无法确认它是否有效。明天进入办公室后,我将对其进行测试。
我的问题帖子中的最后一个更新,我找出了定义ffi.library的正确方法。
我误解了C语言。关键是Ref.Reftype('Char'(或"字符串"简单地传递的" char*"需求;简而言之,Ref.Reftype('void'(或"指针"传递了" void*"的需求;'int*'需要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