当前位置: 首页 > 工具软件 > napi > 使用案例 >

nodejs使用node-ffi-napi 访问dll文件

奚瑾瑜
2023-12-01

用electron做一个访问can卡的上位机

使用node-ffi-napi 访问dll文件,需要安装
ffi-napi
ref-napi
ref-array-napi
ref-struct-napi

安装ffi需要用到node-gyp,安装教程可以百度下

以下是使用过程


需要调用的dll的.h头文件如下,此dll是用来访问can卡的
#ifndef CONTROLCAN_H
#define CONTROLCAN_H

//#include <cvidef.h>	//使用CVI平台开发,请使用该语句。
//接口卡类型定义
#define VCI_USBCAN1		3
#define VCI_USBCAN2		4
#define VCI_USBCAN2A		4
#define VCI_USBCAN_E_U 		20
#define VCI_USBCAN_2E_U 	21

//函数调用返回状态值
#define	STATUS_OK					1
#define STATUS_ERR					0
//1.ZLGCAN系列接口卡信息的数据类型。
typedef  struct  _VCI_BOARD_INFO{   
		USHORT	hw_Version;
		USHORT	fw_Version;
		USHORT	dr_Version;
		USHORT	in_Version;
		USHORT	irq_Num;
		BYTE	can_Num;
		CHAR	str_Serial_Num[20];
		CHAR	str_hw_Type[40];
		USHORT	Reserved[4];
} VCI_BOARD_INFO,*PVCI_BOARD_INFO; 
//2.定义CAN信息帧的数据类型。
typedef  struct  _VCI_CAN_OBJ{
	UINT	ID;
	UINT	TimeStamp;
	BYTE	TimeFlag;
	BYTE	SendType;
	BYTE	RemoteFlag;//是否是远程帧
	BYTE	ExternFlag;//是否是扩展帧
	BYTE	DataLen;
	BYTE	Data[8];
	BYTE	Reserved[3];
}VCI_CAN_OBJ,*PVCI_CAN_OBJ;
//3.定义初始化CAN的数据类型
typedef struct _VCI_INIT_CONFIG{
	DWORD	AccCode;
	DWORD	AccMask;
	DWORD	Reserved;
	UCHAR	Filter;
	UCHAR	Timing0;	
	UCHAR	Timing1;	
	UCHAR	Mode;
}VCI_INIT_CONFIG,*PVCI_INIT_CONFIG;
/ new add struct for filter /
typedef struct _VCI_FILTER_RECORD{
	DWORD ExtFrame;	//是否为扩展帧
	DWORD Start;
	DWORD End;
}VCI_FILTER_RECORD,*PVCI_FILTER_RECORD;
 
#define EXTERNC		extern "C"
EXTERNC DWORD __stdcall VCI_OpenDevice(DWORD DeviceType,DWORD DeviceInd,DWORD Reserved);
EXTERNC DWORD __stdcall VCI_CloseDevice(DWORD DeviceType,DWORD DeviceInd);
EXTERNC DWORD __stdcall VCI_InitCAN(DWORD DeviceType, DWORD DeviceInd, DWORD CANInd, PVCI_INIT_CONFIG pInitConfig);
EXTERNC DWORD __stdcall VCI_ReadBoardInfo(DWORD DeviceType,DWORD DeviceInd,PVCI_BOARD_INFO pInfo);
EXTERNC DWORD __stdcall VCI_SetReference(DWORD DeviceType,DWORD DeviceInd,DWORD CANInd,DWORD RefType,PVOID pData);
EXTERNC ULONG __stdcall VCI_GetReceiveNum(DWORD DeviceType,DWORD DeviceInd,DWORD CANInd);
EXTERNC DWORD __stdcall VCI_ClearBuffer(DWORD DeviceType,DWORD DeviceInd,DWORD CANInd);
EXTERNC DWORD __stdcall VCI_StartCAN(DWORD DeviceType,DWORD DeviceInd,DWORD CANInd);
EXTERNC DWORD __stdcall VCI_ResetCAN(DWORD DeviceType,DWORD DeviceInd,DWORD CANInd);
EXTERNC ULONG __stdcall VCI_Transmit(DWORD DeviceType,DWORD DeviceInd,DWORD CANInd,PVCI_CAN_OBJ pSend,ULONG Len);
EXTERNC ULONG __stdcall VCI_Receive(DWORD DeviceType,DWORD DeviceInd,DWORD CANInd,PVCI_CAN_OBJ pReceive,ULONG Len,INT WaitTime);
/*------------------------------------------------其他补充函数及数据结构描述------------------------------------------------*/
//USB-CAN总线适配器板卡信息的数据类型1,该类型为VCI_FindUsbDevice函数的返回参数。
typedef  struct  _VCI_BOARD_INFO1{
	USHORT	hw_Version;
	USHORT	fw_Version;
	USHORT	dr_Version;
	USHORT	in_Version;
	USHORT	irq_Num;
	BYTE	can_Num;
	BYTE	Reserved;
	CHAR	str_Serial_Num[8];
	CHAR	str_hw_Type[16];
	CHAR	str_Usb_Serial[4][4];
} VCI_BOARD_INFO1,*PVCI_BOARD_INFO1;
//USB-CAN总线适配器板卡信息的数据类型2,该类型为VCI_FindUsbDevice函数的返回参数。为扩展更多的设备
typedef  struct  _VCI_BOARD_INFO2{
	USHORT	hw_Version;
	USHORT	fw_Version;
	USHORT	dr_Version;
	USHORT	in_Version;
	USHORT	irq_Num;
	BYTE	can_Num;
	BYTE	Reserved;
	CHAR	str_Serial_Num[8];
	CHAR	str_hw_Type[16];
	CHAR	str_Usb_Serial[10][4];
} VCI_BOARD_INFO2,*PVCI_BOARD_INFO2;

#define EXTERNC		extern "C"
EXTERNC DWORD __stdcall VCI_GetReference2(DWORD DevType,DWORD DevIndex,DWORD CANIndex,DWORD Reserved,BYTE *pData);
EXTERNC DWORD __stdcall VCI_SetReference2(DWORD DevType,DWORD DevIndex,DWORD CANIndex,DWORD RefType,BYTE *pData);
EXTERNC DWORD __stdcall VCI_ConnectDevice(DWORD DevType,DWORD DevIndex);
EXTERNC DWORD __stdcall VCI_UsbDeviceReset(DWORD DevType,DWORD DevIndex,DWORD Reserved);
EXTERNC DWORD __stdcall VCI_FindUsbDevice(PVCI_BOARD_INFO1 pInfo);
EXTERNC DWORD __stdcall VCI_FindUsbDevice2(PVCI_BOARD_INFO2 pInfo);
#endif

nodejs中安装完成下列包

  "dependencies": {
    "ffi-napi": "^3.1.0",
    "ref-array-napi": "^1.2.1",
    "ref-napi": "^3.0.1",
    "ref-struct-napi": "^1.1.1"
  }

然后在js文件中使用 (注释和解释在代码中)

dll 的调用需要注意dll是64位还是32位的
这里nodejs是64位的,dll也是64位的
否则可能报错

let ffi = require("ffi-napi");
let ref = require('ref-napi');
let ArrayType = require('ref-array-napi');
let StructType = require('ref-struct-napi');

let _VCI_BOARD_INFO = StructType({    //定义结构体
    hw_Version: ref.types.ushort,
    fw_Version: ref.types.ushort,
    dr_Version: ref.types.ushort,
    in_Version: ref.types.ushort,
    irq_Num: ref.types.ushort,
    can_Num: ref.types.byte,
    str_Serial_Num: ArrayType(ref.types.char, 20),    //char str_Serial_Num[20]
    str_hw_Type: ArrayType(ref.types.char, 40),
    Reserved: ArrayType(ref.types.ushort, 4),
})
let _VCI_CAN_OBJ = StructType({  //定义结构体
    ID: ref.types.uint,
    TimeStamp: ref.types.uint,
    TimeFlag: ref.types.byte,
    SendType: ref.types.byte,
    RemoteFlag: ref.types.byte,
    ExternFlag: ref.types.byte,
    DataLen: ref.types.byte,
    Data: ArrayType(ref.types.byte, 8),
    Reserved: ArrayType(ref.types.byte, 3),
})

let _VCI_INIT_CONFIG = StructType({  //定义结构体
    AccCode: ref.types.ulong,        //DWORD 就是 ref.types.ulong
    AccMask: ref.types.ulong,
    Reserved: ref.types.ulong,
    Filter: ref.types.uchar,
    Timing0: ref.types.uchar,
    Timing1: ref.types.uchar,
    Mode: ref.types.uchar,
})
let _VCI_FILTER_RECORD = StructType({  //定义结构体
    ExtFrame: ref.types.ulong,
    Start: ref.types.ulong,
    End: ref.types.ulong,
})
let _VCI_BOARD_INFO1 = StructType({  //定义结构体
    hw_Version: ref.types.ushort,
    fw_Version: ref.types.ushort,
    dr_Version: ref.types.ushort,
    in_Version: ref.types.ushort,
    irq_Num: ref.types.ushort,
    can_Num: ref.types.byte,
    Reserved: ref.types.byte,
    str_Serial_Num: ArrayType(ref.types.char, 8),
    str_hw_Type: ArrayType(ref.types.char, 16),
    str_Usb_Serial: ArrayType(ArrayType(ref.types.char, 4), 4), //char str_Usb_Serial[4][4]
})
let _VCI_BOARD_INFO2 = StructType({   //定义结构体
    hw_Version: ref.types.ushort,
    fw_Version: ref.types.ushort,
    dr_Version: ref.types.ushort,
    in_Version: ref.types.ushort,
    irq_Num: ref.types.ushort,
    can_Num: ref.types.byte,
    Reserved: ref.types.byte,
    str_Serial_Num: ArrayType(ref.types.char, 8),
    str_hw_Type: ArrayType(ref.types.char, 16),
    str_Usb_Serial: ArrayType(ArrayType(ref.types.char, 10), 4),   //char str_Usb_Serial[10][4]
})
let canDLL = ffi.Library('./ControlCAN.dll', {   //定义方法
    'VCI_OpenDevice': [ref.types.ulong, [ref.types.ulong, ref.types.ulong, ref.types.ulong]],
    'VCI_CloseDevice': [ref.types.ulong, [ref.types.ulong, ref.types.ulong]],
    'VCI_StartCAN': [ref.types.ulong, [ref.types.ulong, ref.types.ulong, ref.types.ulong]],
    'VCI_ReadBoardInfo': [ref.types.ulong, [ref.types.ulong, ref.types.ulong, ref.refType(_VCI_BOARD_INFO)]],
    'VCI_InitCAN': [ref.types.ulong, [ref.types.ulong, ref.types.ulong, ref.types.ulong, ref.refType(_VCI_INIT_CONFIG)]],
    'VCI_FindUsbDevice': [ref.types.ulong, [ref.refType(_VCI_BOARD_INFO1)]]
})

//打开设备
let open = canDLL.VCI_OpenDevice(3, 0, 0)  //传入3个DWORD
console.log(open)
//设备初始化
let initconfig = new _VCI_INIT_CONFIG({  //创建一个结构体并赋值
    AccCode: 0x80000008,
    AccCode: 0xFFFFFFFF,
    Filter: 0,
    Timing0: 0x03,
    Timing1: 0x1c,
    Mode: 0
});
let init = canDLL.VCI_InitCAN(3, 0, 0, initconfig.ref())  //传入3个dword和一个结构体指针
console.log(init)

//打开can
let startCan = canDLL.VCI_StartCAN(3, 0, 0);
console.log(startCan)
//打印接口卡信息
let boardinfo = new _VCI_BOARD_INFO();   //创建一个结构体
canDLL.VCI_ReadBoardInfo.async(3, 0, boardinfo.ref(), (err, result) => {
    if (err) {
        console.log(err)
    }
    console.log(result)  //调用成功后,返回1
    console.log("--------------接口卡信息------------------------")
    console.log('hw_Version:'+boardinfo.hw_Version)   //访问结构体内的值
    console.log('fw_Version:'+boardinfo.fw_Version)	
    console.log('dr_Version:'+boardinfo.dr_Version)
    console.log('in_Version:'+boardinfo.in_Version)
    console.log('irq_Num:'+boardinfo.irq_Num)
    console.log('can_Num:'+boardinfo.can_Num)
    console.log(boardinfo.str_Serial_Num)
    console.log(boardinfo.str_hw_Type)
    console.log(boardinfo.Reserved)
})
 类似资料: