如何使用struct返回调用DLL方法



我想构建一个可以从Dahua访问数字视频录制(DVR(产品的电子应用程序。我使用node-ffi访问dhnetsdk.dll从dahua提供的dhnetsdk.dll,可以调用client_init方法来初始化sdk,但是我无法调用client_loginex2方法登录DVR设备。

问题可能是C 指针,但我不确定。代码在下面显示。

  1. client_loginex2 dhnetsdk.h
  2. 中定义的方法
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
);
  1. 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
    ]
  ],
});
  1. 在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;
  1. 实际致电
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

最新更新