Я хочу создать приложение Electron, которое могло бы получить доступ к продукту цифровой видеозаписи (DVR) от Dahua. Я использую node-ffi для доступа к dhnetsdk.dll, предоставленному Dahua, и могу вызвать метод 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
);
- Реализация метода CLIENT_LoginEx2 в index.ts (по 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
]
],
});
- Определение структуры данных NET_DEVICEINFO_Ex в index.ts (ссылка на структуру из 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, приложение Electron зависало и возвращалось, как показано на скриншоте ниже.
DevTools был отключен от страницы. После перезагрузки страницы
DevTools автоматически переподключится.
Снимок экрана 2
Я думал, что это может привести к неправильному определению структуры данных, но я действительно не знаю, как отследить, где ошибаться. Пожалуйста, дайте совет, очень ценю.
ОБНОВЛЕНИЕ 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 - это указатель для возврата кода ошибки из обратного вызова метода.
Полагаю, это может быть причиной сбоя, но не уверен, что кто-нибудь может помочь мне выяснить, в чем проблема, большое спасибо.
ОБНОВЛЕНИЕ 3 мая
Это может работать после некоторых усилий, я переопределил ffi.Library, как показано ниже
Дело в том, что 'char *' нужно передать через ref.refType ('char') или 'string'; 'void *' нужно передать через ref.refType ('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 для тестирования кода, я не могу подтвердить, работает он или нет. Я проверю это после входа в офис завтра.