• 使用C#使用Windows的HID通信


    本文转载于:https://blog.csdn.net/u010875635/article/details/73321066

    Windows使用HID通信相对比较简单,HID都是通过PID、VID信息来查找连接的,相比于串口,几乎无变化,连接无需人工选择,十分方便,也不需要驱动。

    下面上实例,PID为0x003f,VID为0x04D8,支持发送接收数据显示到UI,使用C#来编写,调用的是windows api(create file、read file、write file)。

    本实例将HID接口分成3层,支持自动连接、断开状态通知,异步收发数据,单个数据包大小为64bytes(因为从设备的数据包设定为64bytes,保持一致)。

    接口分为两层,第一层将create file、read file、write file封装,第二层再封装自动连接、异步收发。

    Hid.cs -> HIDInterface.cs -> 应用

    注意,这里所有数据都是64bytes,但是有用数据并非这么多,所以设定为第一个数据为后面数据实际长度,若需要修改定义,请在HIDInterface.cs的Send与HidDataReceived函数中修改处理方法即可。

    Hid.cs
      1 using System;
      2 using System.Collections.Generic;
      3 using System.Runtime.InteropServices;
      4 using System.IO;
      5 using Microsoft.Win32.SafeHandles;
      6 using System.Windows;
      7 
      8 namespace HID_SIMPLE.HID
      9 {
     10     public class report : EventArgs
     11     {
     12         public readonly byte reportID;
     13         public readonly byte[] reportBuff;
     14         public report(byte id, byte[] arrayBuff)
     15         {
     16             reportID = id;
     17             reportBuff = arrayBuff;
     18         }
     19     }
     20     public class Hid : object
     21     {
     22         private IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);
     23         private const int MAX_USB_DEVICES = 64;
     24         private bool deviceOpened = false;
     25         private FileStream hidDevice = null;
     26         private IntPtr hHubDevice;
     27         
     28         int outputReportLength;//输出报告长度,包刮一个字节的报告ID
     29         public int OutputReportLength { get { return outputReportLength; } }
     30         int inputReportLength;//输入报告长度,包刮一个字节的报告ID   
     31         public int InputReportLength { get { return inputReportLength; } }
     32 
     33         /// <summary>
     34         /// 打开指定信息的设备
     35         /// </summary>
     36         /// <param name="vID">设备的vID</param>
     37         /// <param name="pID">设备的pID</param>
     38         /// <param name="serial">设备的serial</param>
     39         /// <returns></returns>
     40         public HID_RETURN OpenDevice(UInt16 vID, UInt16 pID, string serial)
     41         {
     42             if (deviceOpened == false)
     43             {
     44                 //获取连接的HID列表
     45                 List<string> deviceList = new List<string>();
     46                 GetHidDeviceList(ref deviceList);
     47                 if (deviceList.Count == 0)
     48                     return HID_RETURN.NO_DEVICE_CONECTED;
     49                 for (int i = 0; i < deviceList.Count; i++)
     50                 {
     51                     IntPtr device = CreateFile(deviceList[i],
     52                                                 DESIREDACCESS.GENERIC_READ | DESIREDACCESS.GENERIC_WRITE,
     53                                                 0,
     54                                                 0,
     55                                                 CREATIONDISPOSITION.OPEN_EXISTING,
     56                                                 FLAGSANDATTRIBUTES.FILE_FLAG_OVERLAPPED,
     57                                                 0);
     58                     if (device != INVALID_HANDLE_VALUE)
     59                     {
     60                         HIDD_ATTRIBUTES attributes;
     61                         IntPtr serialBuff = Marshal.AllocHGlobal(512);
     62                         HidD_GetAttributes(device, out attributes);
     63                         HidD_GetSerialNumberString(device, serialBuff, 512);
     64                         string deviceStr = Marshal.PtrToStringAuto(serialBuff);
     65                         Marshal.FreeHGlobal(serialBuff);
     66                         if (attributes.VendorID == vID && attributes.ProductID == pID && deviceStr.Contains(serial))
     67                         {
     68                             IntPtr preparseData;
     69                             HIDP_CAPS caps;
     70                             HidD_GetPreparsedData(device, out preparseData);
     71                             HidP_GetCaps(preparseData, out caps);
     72                             HidD_FreePreparsedData(preparseData);
     73                             outputReportLength = caps.OutputReportByteLength;
     74                             inputReportLength = caps.InputReportByteLength;
     75 
     76                             hidDevice = new FileStream(new SafeFileHandle(device, false), FileAccess.ReadWrite, inputReportLength, true);
     77                             deviceOpened = true;
     78                             BeginAsyncRead();
     79 
     80                             hHubDevice = device;
     81                             return HID_RETURN.SUCCESS;
     82                         }
     83                     }
     84                 }
     85                 return HID_RETURN.DEVICE_NOT_FIND;
     86             }
     87             else
     88                 return HID_RETURN.DEVICE_OPENED;
     89         }
     90 
     91         /// <summary>
     92         /// 关闭打开的设备
     93         /// </summary>
     94         public void CloseDevice()
     95         {
     96             if (deviceOpened == true)
     97             {
     98                 deviceOpened = false;
     99                 hidDevice.Close();
    100             }
    101         }
    102 
    103         /// <summary>
    104         /// 开始一次异步读
    105         /// </summary>
    106         private void BeginAsyncRead()
    107         {
    108             byte[] inputBuff = new byte[InputReportLength];
    109             hidDevice.BeginRead(inputBuff, 0, InputReportLength, new AsyncCallback(ReadCompleted), inputBuff);
    110         }
    111 
    112         /// <summary>
    113         /// 异步读取结束,发出有数据到达事件
    114         /// </summary>
    115         /// <param name="iResult">这里是输入报告的数组</param>
    116         private void ReadCompleted(IAsyncResult iResult)
    117         {
    118             byte[] readBuff = (byte[])(iResult.AsyncState);
    119             try
    120             {
    121                 hidDevice.EndRead(iResult);//读取结束,如果读取错误就会产生一个异常
    122                 byte[] reportData = new byte[readBuff.Length - 1];
    123                 for (int i = 1; i < readBuff.Length; i++)
    124                     reportData[i - 1] = readBuff[i];
    125                 report e = new report(readBuff[0], reportData);
    126                 OnDataReceived(e); //发出数据到达消息
    127                 if (!deviceOpened) return;
    128                 BeginAsyncRead();//启动下一次读操作
    129             }
    130             catch //读写错误,设备已经被移除
    131             {
    132                 //MyConsole.WriteLine("设备无法连接,请重新插入设备");
    133                 EventArgs ex = new EventArgs();
    134                 OnDeviceRemoved(ex);//发出设备移除消息
    135                 CloseDevice();
    136 
    137             }
    138         }
    139 
    140         public delegate void DelegateDataReceived(object sender, report e);
    141         //public event EventHandler<ConnectEventArg> StatusConnected;
    142        
    143         public DelegateDataReceived DataReceived;
    144 
    145         /// <summary>
    146         /// 事件:数据到达,处理此事件以接收输入数据
    147         /// </summary>
    148         
    149         protected virtual void OnDataReceived(report e)
    150         {
    151             if (DataReceived != null) DataReceived(this, e);
    152         }
    153 
    154         /// <summary>
    155         /// 事件:设备断开
    156         /// </summary>
    157 
    158         public delegate void DelegateStatusConnected(object sender, EventArgs e);
    159         public DelegateStatusConnected DeviceRemoved;
    160         protected virtual void OnDeviceRemoved(EventArgs e)
    161         {
    162             if (DeviceRemoved != null) DeviceRemoved(this,e);
    163         }
    164 
    165         /// <summary>
    166         /// 
    167         /// </summary>
    168         /// <param name="buffer"></param>
    169         /// <returns></returns>
    170         public HID_RETURN Write(report r)
    171         {
    172             if (deviceOpened)
    173             {
    174                 try
    175                 {
    176                     byte[] buffer = new byte[outputReportLength];
    177                     buffer[0] = r.reportID;
    178                     int maxBufferLength = 0;
    179                     if (r.reportBuff.Length < outputReportLength - 1)
    180                         maxBufferLength = r.reportBuff.Length;
    181                     else
    182                         maxBufferLength = outputReportLength - 1;
    183 
    184                     for (int i = 0; i < maxBufferLength; i++)
    185                         buffer[i + 1] = r.reportBuff[i];
    186                     hidDevice.Write(buffer, 0, OutputReportLength);
    187                     return HID_RETURN.SUCCESS;
    188                 }
    189                 catch
    190                 {
    191                     EventArgs ex = new EventArgs();
    192                     OnDeviceRemoved(ex);//发出设备移除消息
    193                     CloseDevice();
    194                     return HID_RETURN.NO_DEVICE_CONECTED;
    195                 }
    196             }
    197             return HID_RETURN.WRITE_FAILD;
    198         }
    199 
    200         /// <summary>
    201         /// 获取所有连接的hid的设备路径
    202         /// </summary>
    203         /// <returns>包含每个设备路径的字符串数组</returns>
    204         public static void GetHidDeviceList(ref List<string> deviceList)
    205         {
    206             Guid hUSB = Guid.Empty;
    207             uint index = 0;
    208 
    209             deviceList.Clear();
    210             // 取得hid设备全局id
    211             HidD_GetHidGuid(ref hUSB);
    212             //取得一个包含所有HID接口信息集合的句柄
    213             IntPtr hidInfoSet = SetupDiGetClassDevs(ref hUSB, 0, IntPtr.Zero, DIGCF.DIGCF_PRESENT | DIGCF.DIGCF_DEVICEINTERFACE);
    214             if (hidInfoSet != IntPtr.Zero)
    215             {
    216                 SP_DEVICE_INTERFACE_DATA interfaceInfo = new SP_DEVICE_INTERFACE_DATA();
    217                 interfaceInfo.cbSize = Marshal.SizeOf(interfaceInfo);
    218                 //查询集合中每一个接口
    219                 for (index = 0; index < MAX_USB_DEVICES; index++)
    220                 {
    221                     //得到第index个接口信息
    222                     if (SetupDiEnumDeviceInterfaces(hidInfoSet, IntPtr.Zero, ref hUSB, index, ref interfaceInfo))
    223                     {
    224                         int buffsize = 0;
    225                         // 取得接口详细信息:第一次读取错误,但可以取得信息缓冲区的大小
    226                         SetupDiGetDeviceInterfaceDetail(hidInfoSet, ref interfaceInfo, IntPtr.Zero, buffsize, ref buffsize, null);
    227                         //构建接收缓冲
    228                         IntPtr pDetail = Marshal.AllocHGlobal(buffsize);
    229                         SP_DEVICE_INTERFACE_DETAIL_DATA detail = new SP_DEVICE_INTERFACE_DETAIL_DATA();
    230                         detail.cbSize = Marshal.SizeOf(typeof(SP_DEVICE_INTERFACE_DETAIL_DATA));
    231                         Marshal.StructureToPtr(detail, pDetail, false);
    232                         if (SetupDiGetDeviceInterfaceDetail(hidInfoSet, ref interfaceInfo, pDetail, buffsize, ref buffsize, null))
    233                         {
    234                             deviceList.Add(Marshal.PtrToStringAuto((IntPtr)((int)pDetail + 4)));
    235                         }
    236                         Marshal.FreeHGlobal(pDetail);
    237                     }
    238                 }
    239             }
    240             SetupDiDestroyDeviceInfoList(hidInfoSet);
    241             //return deviceList.ToArray();
    242         }
    243 
    244         #region<连接USB返回的结构体信息>
    245         /// <summary>
    246         /// 连接USB返回的结构体信息
    247         /// </summary>
    248         public enum HID_RETURN
    249         {
    250             SUCCESS = 0,
    251             NO_DEVICE_CONECTED,
    252             DEVICE_NOT_FIND,
    253             DEVICE_OPENED,
    254             WRITE_FAILD,
    255             READ_FAILD
    256 
    257         }
    258         #endregion
    259 
    260 
    261         // 以下是调用windows的API的函数
    262         /// <summary>
    263         /// The HidD_GetHidGuid routine returns the device interface GUID for HIDClass devices.
    264         /// </summary>
    265         /// <param name="HidGuid">a caller-allocated GUID buffer that the routine uses to return the device interface GUID for HIDClass devices.</param>
    266         [DllImport("hid.dll")]
    267         private static extern void HidD_GetHidGuid(ref Guid HidGuid);
    268 
    269         /// <summary>
    270         /// The SetupDiGetClassDevs function returns a handle to a device information set that contains requested device information elements for a local machine. 
    271         /// </summary>
    272         /// <param name="ClassGuid">GUID for a device setup class or a device interface class. </param>
    273         /// <param name="Enumerator">A pointer to a NULL-terminated string that supplies the name of a PnP enumerator or a PnP device instance identifier. </param>
    274         /// <param name="HwndParent">A handle of the top-level window to be used for a user interface</param>
    275         /// <param name="Flags">A variable  that specifies control options that filter the device information elements that are added to the device information set. </param>
    276         /// <returns>a handle to a device information set </returns>
    277         [DllImport("setupapi.dll", SetLastError = true)]
    278         private static extern IntPtr SetupDiGetClassDevs(ref Guid ClassGuid, uint Enumerator, IntPtr HwndParent, DIGCF Flags);
    279 
    280         /// <summary>
    281         /// The SetupDiDestroyDeviceInfoList function deletes a device information set and frees all associated memory.
    282         /// </summary>
    283         /// <param name="DeviceInfoSet">A handle to the device information set to delete.</param>
    284         /// <returns>returns TRUE if it is successful. Otherwise, it returns FALSE </returns>
    285         [DllImport("setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)]
    286         private static extern Boolean SetupDiDestroyDeviceInfoList(IntPtr deviceInfoSet);
    287 
    288         /// <summary>
    289         /// The SetupDiEnumDeviceInterfaces function enumerates the device interfaces that are contained in a device information set. 
    290         /// </summary>
    291         /// <param name="deviceInfoSet">A pointer to a device information set that contains the device interfaces for which to return information</param>
    292         /// <param name="deviceInfoData">A pointer to an SP_DEVINFO_DATA structure that specifies a device information element in DeviceInfoSet</param>
    293         /// <param name="interfaceClassGuid">a GUID that specifies the device interface class for the requested interface</param>
    294         /// <param name="memberIndex">A zero-based index into the list of interfaces in the device information set</param>
    295         /// <param name="deviceInterfaceData">a caller-allocated buffer that contains a completed SP_DEVICE_INTERFACE_DATA structure that identifies an interface that meets the search parameters</param>
    296         /// <returns></returns>
    297         [DllImport("setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)]
    298         private static extern Boolean SetupDiEnumDeviceInterfaces(IntPtr deviceInfoSet, IntPtr deviceInfoData, ref Guid interfaceClassGuid, UInt32 memberIndex, ref SP_DEVICE_INTERFACE_DATA deviceInterfaceData);
    299 
    300         /// <summary>
    301         /// The SetupDiGetDeviceInterfaceDetail function returns details about a device interface.
    302         /// </summary>
    303         /// <param name="deviceInfoSet">A pointer to the device information set that contains the interface for which to retrieve details</param>
    304         /// <param name="deviceInterfaceData">A pointer to an SP_DEVICE_INTERFACE_DATA structure that specifies the interface in DeviceInfoSet for which to retrieve details</param>
    305         /// <param name="deviceInterfaceDetailData">A pointer to an SP_DEVICE_INTERFACE_DETAIL_DATA structure to receive information about the specified interface</param>
    306         /// <param name="deviceInterfaceDetailDataSize">The size of the DeviceInterfaceDetailData buffer</param>
    307         /// <param name="requiredSize">A pointer to a variable that receives the required size of the DeviceInterfaceDetailData buffer</param>
    308         /// <param name="deviceInfoData">A pointer buffer to receive information about the device that supports the requested interface</param>
    309         /// <returns></returns>
    310         [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)]
    311         private static extern bool SetupDiGetDeviceInterfaceDetail(IntPtr deviceInfoSet, ref SP_DEVICE_INTERFACE_DATA deviceInterfaceData, IntPtr deviceInterfaceDetailData, int deviceInterfaceDetailDataSize, ref int requiredSize, SP_DEVINFO_DATA deviceInfoData);
    312 
    313         /// <summary>
    314         /// The HidD_GetAttributes routine returns the attributes of a specified top-level collection.
    315         /// </summary>
    316         /// <param name="HidDeviceObject">Specifies an open handle to a top-level collection</param>
    317         /// <param name="Attributes">a caller-allocated HIDD_ATTRIBUTES structure that returns the attributes of the collection specified by HidDeviceObject</param>
    318         /// <returns></returns>
    319         [DllImport("hid.dll")]
    320         private static extern Boolean HidD_GetAttributes(IntPtr hidDeviceObject, out HIDD_ATTRIBUTES attributes);
    321         /// <summary>
    322         /// The HidD_GetSerialNumberString routine returns the embedded string of a top-level collection that identifies the serial number of the collection's physical device.
    323         /// </summary>
    324         /// <param name="HidDeviceObject">Specifies an open handle to a top-level collection</param>
    325         /// <param name="Buffer">a caller-allocated buffer that the routine uses to return the requested serial number string</param>
    326         /// <param name="BufferLength">Specifies the length, in bytes, of a caller-allocated buffer provided at Buffer</param>
    327         /// <returns></returns>
    328         [DllImport("hid.dll")]
    329         private static extern Boolean HidD_GetSerialNumberString(IntPtr hidDeviceObject, IntPtr buffer, int bufferLength);
    330 
    331         /// <summary>
    332         /// The HidD_GetPreparsedData routine returns a top-level collection's preparsed data.
    333         /// </summary>
    334         /// <param name="hidDeviceObject">Specifies an open handle to a top-level collection. </param>
    335         /// <param name="PreparsedData">Pointer to the address of a routine-allocated buffer that contains a collection's preparsed data in a _HIDP_PREPARSED_DATA structure.</param>
    336         /// <returns>HidD_GetPreparsedData returns TRUE if it succeeds; otherwise, it returns FALSE.</returns>
    337         [DllImport("hid.dll")]
    338         private static extern Boolean HidD_GetPreparsedData(IntPtr hidDeviceObject, out IntPtr PreparsedData);
    339 
    340         [DllImport("hid.dll")]
    341         private static extern Boolean HidD_FreePreparsedData(IntPtr PreparsedData);
    342 
    343         [DllImport("hid.dll")]
    344         private static extern uint HidP_GetCaps(IntPtr PreparsedData, out HIDP_CAPS Capabilities);
    345 
    346 
    347         /// <summary>
    348         /// This function creates, opens, or truncates a file, COM port, device, service, or console. 
    349         /// </summary>
    350         /// <param name="fileName">a null-terminated string that specifies the name of the object</param>
    351         /// <param name="desiredAccess">Type of access to the object</param>
    352         /// <param name="shareMode">Share mode for object</param>
    353         /// <param name="securityAttributes">Ignored; set to NULL</param>
    354         /// <param name="creationDisposition">Action to take on files that exist, and which action to take when files do not exist</param>
    355         /// <param name="flagsAndAttributes">File attributes and flags for the file</param>
    356         /// <param name="templateFile">Ignored</param>
    357         /// <returns>An open handle to the specified file indicates success</returns>
    358         [DllImport("kernel32.dll", SetLastError = true)]
    359         private static extern IntPtr CreateFile(string fileName, uint desiredAccess, uint shareMode, uint securityAttributes, uint creationDisposition, uint flagsAndAttributes, uint templateFile);
    360 
    361         /// <summary>
    362         /// This function closes an open object handle.
    363         /// </summary>
    364         /// <param name="hObject">Handle to an open object</param>
    365         /// <returns></returns>
    366         [DllImport("kernel32.dll")]
    367         private static extern int CloseHandle(IntPtr hObject);
    368 
    369         /// <summary>
    370         /// This function reads data from a file, starting at the position indicated by the file pointer.
    371         /// </summary>
    372         /// <param name="file">Handle to the file to be read</param>
    373         /// <param name="buffer">Pointer to the buffer that receives the data read from the file </param>
    374         /// <param name="numberOfBytesToRead">Number of bytes to be read from the file</param>
    375         /// <param name="numberOfBytesRead">Pointer to the number of bytes read</param>
    376         /// <param name="lpOverlapped">Unsupported; set to NULL</param>
    377         /// <returns></returns>
    378         [DllImport("Kernel32.dll", SetLastError = true)]
    379         private static extern bool ReadFile(IntPtr file, byte[] buffer, uint numberOfBytesToRead, out uint numberOfBytesRead, IntPtr lpOverlapped);
    380 
    381         /// <summary>
    382         ///  This function writes data to a file
    383         /// </summary>
    384         /// <param name="file">Handle to the file to be written to</param>
    385         /// <param name="buffer">Pointer to the buffer containing the data to write to the file</param>
    386         /// <param name="numberOfBytesToWrite">Number of bytes to write to the file</param>
    387         /// <param name="numberOfBytesWritten">Pointer to the number of bytes written by this function call</param>
    388         /// <param name="lpOverlapped">Unsupported; set to NULL</param>
    389         /// <returns></returns>
    390         [DllImport("Kernel32.dll", SetLastError = true)]
    391         private static extern bool WriteFile(IntPtr file, byte[] buffer, uint numberOfBytesToWrite, out uint numberOfBytesWritten, IntPtr lpOverlapped);
    392 
    393         /// <summary>
    394         /// Registers the device or type of device for which a window will receive notifications
    395         /// </summary>
    396         /// <param name="recipient">A handle to the window or service that will receive device events for the devices specified in the NotificationFilter parameter</param>
    397         /// <param name="notificationFilter">A pointer to a block of data that specifies the type of device for which notifications should be sent</param>
    398         /// <param name="flags">A Flags that specify the handle type</param>
    399         /// <returns>If the function succeeds, the return value is a device notification handle</returns>
    400         [DllImport("User32.dll", SetLastError = true)]
    401         private static extern IntPtr RegisterDeviceNotification(IntPtr recipient, IntPtr notificationFilter, int flags);
    402 
    403         /// <summary>
    404         /// Closes the specified device notification handle.
    405         /// </summary>
    406         /// <param name="handle">Device notification handle returned by the RegisterDeviceNotification function</param>
    407         /// <returns></returns>
    408         [DllImport("user32.dll", SetLastError = true)]
    409         private static extern bool UnregisterDeviceNotification(IntPtr handle);
    410     }
    411     #region
    412     /// <summary>
    413     /// SP_DEVICE_INTERFACE_DATA structure defines a device interface in a device information set.
    414     /// </summary>
    415     public struct SP_DEVICE_INTERFACE_DATA
    416     {
    417         public int cbSize;
    418         public Guid interfaceClassGuid;
    419         public int flags;
    420         public int reserved;
    421     }
    422 
    423     /// <summary>
    424     /// SP_DEVICE_INTERFACE_DETAIL_DATA structure contains the path for a device interface.
    425     /// </summary>
    426     [StructLayout(LayoutKind.Sequential, Pack = 2)]
    427     internal struct SP_DEVICE_INTERFACE_DETAIL_DATA
    428     {
    429         internal int cbSize;
    430         internal short devicePath;
    431     }
    432 
    433     /// <summary>
    434     /// SP_DEVINFO_DATA structure defines a device instance that is a member of a device information set.
    435     /// </summary>
    436     [StructLayout(LayoutKind.Sequential)]
    437     public class SP_DEVINFO_DATA
    438     {
    439         public int cbSize = Marshal.SizeOf(typeof(SP_DEVINFO_DATA));
    440         public Guid classGuid = Guid.Empty; // temp
    441         public int devInst = 0; // dumy
    442         public int reserved = 0;
    443     }
    444     /// <summary>
    445     /// Flags controlling what is included in the device information set built by SetupDiGetClassDevs
    446     /// </summary>
    447     public enum DIGCF
    448     {
    449         DIGCF_DEFAULT = 0x00000001, // only valid with DIGCF_DEVICEINTERFACE                 
    450         DIGCF_PRESENT = 0x00000002,
    451         DIGCF_ALLCLASSES = 0x00000004,
    452         DIGCF_PROFILE = 0x00000008,
    453         DIGCF_DEVICEINTERFACE = 0x00000010
    454     }
    455     /// <summary>
    456     /// The HIDD_ATTRIBUTES structure contains vendor information about a HIDClass device
    457     /// </summary>
    458     public struct HIDD_ATTRIBUTES
    459     {
    460         public int Size;
    461         public ushort VendorID;
    462         public ushort ProductID;
    463         public ushort VersionNumber;
    464     }
    465 
    466     public struct HIDP_CAPS
    467     {
    468         public ushort Usage;
    469         public ushort UsagePage;
    470         public ushort InputReportByteLength;
    471         public ushort OutputReportByteLength;
    472         [MarshalAs(UnmanagedType.ByValArray, SizeConst = 17)]
    473         public ushort[] Reserved;
    474         public ushort NumberLinkCollectionNodes;
    475         public ushort NumberInputButtonCaps;
    476         public ushort NumberInputValueCaps;
    477         public ushort NumberInputDataIndices;
    478         public ushort NumberOutputButtonCaps;
    479         public ushort NumberOutputValueCaps;
    480         public ushort NumberOutputDataIndices;
    481         public ushort NumberFeatureButtonCaps;
    482         public ushort NumberFeatureValueCaps;
    483         public ushort NumberFeatureDataIndices;
    484     }
    485     /// <summary>
    486     /// Type of access to the object. 
    487     ///</summary>
    488     static class DESIREDACCESS
    489     {
    490         public const uint GENERIC_READ = 0x80000000;
    491         public const uint GENERIC_WRITE = 0x40000000;
    492         public const uint GENERIC_EXECUTE = 0x20000000;
    493         public const uint GENERIC_ALL = 0x10000000;
    494     }
    495     /// <summary>
    496     /// Action to take on files that exist, and which action to take when files do not exist. 
    497     /// </summary>
    498     static class CREATIONDISPOSITION
    499     {
    500         public const uint CREATE_NEW = 1;
    501         public const uint CREATE_ALWAYS = 2;
    502         public const uint OPEN_EXISTING = 3;
    503         public const uint OPEN_ALWAYS = 4;
    504         public const uint TRUNCATE_EXISTING = 5;
    505     }
    506     /// <summary>
    507     /// File attributes and flags for the file. 
    508     /// </summary>
    509     static class FLAGSANDATTRIBUTES
    510     {
    511         public const uint FILE_FLAG_WRITE_THROUGH = 0x80000000;
    512         public const uint FILE_FLAG_OVERLAPPED = 0x40000000;
    513         public const uint FILE_FLAG_NO_BUFFERING = 0x20000000;
    514         public const uint FILE_FLAG_RANDOM_ACCESS = 0x10000000;
    515         public const uint FILE_FLAG_SEQUENTIAL_SCAN = 0x08000000;
    516         public const uint FILE_FLAG_DELETE_ON_CLOSE = 0x04000000;
    517         public const uint FILE_FLAG_BACKUP_SEMANTICS = 0x02000000;
    518         public const uint FILE_FLAG_POSIX_SEMANTICS = 0x01000000;
    519         public const uint FILE_FLAG_OPEN_REPARSE_POINT = 0x00200000;
    520         public const uint FILE_FLAG_OPEN_NO_RECALL = 0x00100000;
    521         public const uint FILE_FLAG_FIRST_PIPE_INSTANCE = 0x00080000;
    522     }
    523     /// <summary>
    524     /// Serves as a standard header for information related to a device event reported through the WM_DEVICECHANGE message.
    525     /// </summary>
    526     [StructLayout(LayoutKind.Sequential)]
    527     public struct DEV_BROADCAST_HDR
    528     {
    529         public int dbcc_size;
    530         public int dbcc_devicetype;
    531         public int dbcc_reserved;
    532     }
    533     /// <summary>
    534     /// Contains information about a class of devices
    535     /// </summary>
    536     [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
    537     public struct DEV_BROADCAST_DEVICEINTERFACE
    538     {
    539         public int dbcc_size;
    540         public int dbcc_devicetype;
    541         public int dbcc_reserved;
    542         public Guid dbcc_classguid;
    543         [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 255)]
    544         public string dbcc_name;
    545     }
    546     #endregion
    547 }
    View Code
    HIDInterface.cs
      1 using System;
      2 using System.Collections;
      3 using System.Collections.Generic;
      4 using System.ComponentModel;
      5 using System.IO;
      6 using System.Text;
      7 using System.Threading;
      8 using System.Windows.Forms;
      9 
     10 namespace HID_SIMPLE.HID
     11 {
     12     public class HIDInterface : IDisposable
     13     {
     14 
     15         public enum MessagesType
     16         {
     17             Message,
     18             Error
     19         }
     20 
     21         public struct ReusltString
     22         {
     23             public bool Result;
     24             public string message;
     25         }
     26 
     27         public struct HidDevice
     28         {
     29             public UInt16 vID;
     30             public UInt16 pID;
     31             public string serial;
     32         }
     33         HidDevice lowHidDevice = new HidDevice();
     34 
     35         public delegate void DelegateDataReceived(object sender, byte[] data);
     36         public DelegateDataReceived DataReceived;
     37  
     38         public delegate void DelegateStatusConnected(object sender, bool isConnect);
     39         public DelegateStatusConnected StatusConnected;
     40 
     41         public bool bConnected = false;
     42 
     43 
     44         public Hid oSp = new Hid();
     45         private static HIDInterface m_oInstance;
     46 
     47         public struct TagInfo
     48         {
     49             public string AntennaPort;
     50             public string EPC;
     51         }
     52 
     53         public HIDInterface()
     54         {
     55             m_oInstance = this;
     56             oSp.DataReceived = HidDataReceived;
     57             oSp.DeviceRemoved = HidDeviceRemoved;
     58         }
     59 
     60         protected virtual void RaiseEventConnectedState(bool isConnect)
     61         {
     62             if (null != StatusConnected) StatusConnected(this, isConnect);
     63         }
     64 
     65         protected virtual void RaiseEventDataReceived(byte[] buf)
     66         {
     67             if(null != DataReceived) DataReceived(this, buf);
     68         }
     69 
     70         public void AutoConnect(HidDevice hidDevice)
     71         {
     72             lowHidDevice = hidDevice;
     73             ContinueConnectFlag = true;
     74             ReadWriteThread.DoWork += ReadWriteThread_DoWork;
     75             ReadWriteThread.WorkerSupportsCancellation = true;
     76             ReadWriteThread.RunWorkerAsync();    //Recommend performing USB read/write operations in a separate thread.  Otherwise,
     77         }
     78 
     79         public void StopAutoConnect()
     80         {
     81             try
     82             {
     83                 ContinueConnectFlag = false;
     84                 Dispose();
     85             }
     86             catch
     87             {
     88                  
     89             }
     90         }
     91 
     92         ~HIDInterface()
     93         {
     94             Dispose();
     95         }
     96 
     97         public bool Connect(HidDevice hidDevice)
     98         {
     99             ReusltString result = new ReusltString();
    100 
    101             Hid.HID_RETURN hdrtn = oSp.OpenDevice(hidDevice.vID, hidDevice.pID, hidDevice.serial);
    102 
    103             if (hdrtn == Hid.HID_RETURN.SUCCESS)
    104             {
    105 
    106                 bConnected = true;
    107 
    108                 #region 消息通知
    109                 result.Result = true;
    110                 result.message = "Connect Success!";
    111                 RaiseEventConnectedState(result.Result);
    112                 #endregion 
    113 
    114                 
    115                 return true;
    116             }
    117 
    118             bConnected = false;
    119 
    120             #region 消息通知
    121             result.Result = false;
    122             result.message = "Device Connect Error";
    123             RaiseEventConnectedState(result.Result);
    124             
    125             #endregion 
    126             return false;
    127         }
    128 
    129 
    130         public bool Send(byte[] byData)
    131         {
    132             byte[] sendtemp = new byte[byData.Length + 1];
    133             sendtemp[0] = (byte)byData.Length;
    134             Array.Copy(byData, 0, sendtemp, 1, byData.Length);
    135 
    136             Hid.HID_RETURN hdrtn = oSp.Write(new report(0, sendtemp));
    137 
    138             if (hdrtn != Hid.HID_RETURN.SUCCESS)
    139             {
    140                 return false;
    141             }
    142             return true;
    143         }
    144 
    145         public bool Send(string strData)
    146         {
    147             //获得报文的编码字节
    148             byte[] data = Encoding.Unicode.GetBytes(strData);
    149             return Send(data);
    150         }
    151 
    152 
    153 
    154         public void DisConnect()
    155         {
    156             bConnected = false;
    157 
    158             Thread.Sleep(200);
    159             if (oSp != null)
    160             {
    161                 oSp.CloseDevice();
    162             }
    163         }
    164 
    165 
    166         void HidDeviceRemoved(object sender, EventArgs e)
    167         {
    168             bConnected = false;
    169             #region 消息通知
    170             ReusltString result = new ReusltString();
    171             result.Result = false;
    172             result.message = "Device Remove";
    173             RaiseEventConnectedState(result.Result);
    174             #endregion
    175             if (oSp != null)
    176             {
    177                 oSp.CloseDevice();
    178             }
    179 
    180         }
    181 
    182         public void HidDataReceived(object sender, report e)
    183         {
    184           
    185             try
    186             {
    187                 //第一个字节为数据长度,因为Device 的HID数据固定长度为64字节,取有效数据
    188                 byte[] buf = new byte[e.reportBuff[0]];
    189                 Array.Copy(e.reportBuff, 1, buf, 0, e.reportBuff[0]);
    190 
    191                 //推送数据
    192                 RaiseEventDataReceived(buf);
    193             }
    194             catch
    195             {
    196                 #region 消息通知
    197                 ReusltString result = new ReusltString();
    198                 result.Result = false;
    199                 result.message = "Receive Error";
    200                 RaiseEventConnectedState(result.Result);
    201                 #endregion
    202             }
    203  
    204         }
    205 
    206         public void Dispose()
    207         {
    208             try
    209             {
    210                 this.DisConnect();
    211                 oSp.DataReceived -= HidDataReceived;
    212                 oSp.DeviceRemoved -= HidDeviceRemoved;
    213                 ReadWriteThread.DoWork -= ReadWriteThread_DoWork;
    214                 ReadWriteThread.CancelAsync();
    215                 ReadWriteThread.Dispose();
    216             }
    217             catch
    218             { }
    219         }
    220 
    221         Boolean ContinueConnectFlag = true;
    222         private BackgroundWorker ReadWriteThread = new BackgroundWorker();
    223         private void ReadWriteThread_DoWork(object sender, DoWorkEventArgs e)
    224         {
    225             while (ContinueConnectFlag)
    226             {
    227                 try
    228                 {
    229                     if (!bConnected)
    230                     {
    231                         Connect(lowHidDevice);
    232                         
    233                     }
    234                     Thread.Sleep(500);
    235                 }
    236                 catch { }
    237             }
    238         }
    239 
    240     }
    241 }
    View Code

    调用如下:


     1 #region parameter Define
     2 HIDInterface hid = new HIDInterface();
     3 
     4 
     5 struct connectStatusStruct
     6 {
     7     public bool preStatus;
     8     public bool curStatus;
     9 }
    10 
    11 connectStatusStruct connectStatus = new connectStatusStruct();
    12 
    13 //推送连接状态信息
    14 public delegate void isConnectedDelegate(bool isConnected);
    15 public isConnectedDelegate isConnectedFunc;
    16 
    17 
    18 //推送接收数据信息
    19 public delegate void PushReceiveDataDele(byte[] datas);
    20 public PushReceiveDataDele pushReceiveData;
    21 
    22 #endregion
    23 
    24 //第一步需要初始化,传入vid、pid,并开启自动连接
    25 public void Initial()
    26 { 
    27 
    28     hid.StatusConnected = StatusConnected;
    29     hid.DataReceived = DataReceived;
    30 
    31     HIDInterface.HidDevice hidDevice = new HIDInterface.HidDevice();
    32     hidDevice.vID =0x04D8;
    33     hidDevice.pID = 0x003F;
    34     hidDevice.serial = "";
    35     hid.AutoConnect(hidDevice);
    36 
    37 }
    38 
    39 //不使用则关闭
    40 public void Close()
    41 {
    42     hid.StopAutoConnect();
    43 }
    44 
    45 //发送数据
    46 public bool SendBytes(byte[] data)
    47 {
    48             
    49     return hid.Send(data);
    50             
    51 }
    52 
    53 //接受到数据
    54 public void DataReceived(object sender, byte[] e)
    55 {
    56     if (pushReceiveData != null)
    57         pushReceiveData(e);
    58 }
    59 
    60 //状态改变接收
    61 public void StatusConnected(object sender, bool isConnect)
    62 {
    63     connectStatus.curStatus = isConnect;
    64     if (connectStatus.curStatus == connectStatus.preStatus)  //connect
    65         return;
    66     connectStatus.preStatus = connectStatus.curStatus;
    67 
    68     if(connectStatus.curStatus)
    69     {
    70         isConnectedFunc(true);
    71         //ReportMessage(MessagesType.Message, "连接成功");
    72     }
    73     else //disconnect
    74     {
    75         isConnectedFunc(false);
    76         //ReportMessage(MessagesType.Error, "无法连接");
    77     }
    78 }
  • 相关阅读:
    【对拍√】
    hdu5791 TWO
    luogu P1220 关路灯
    【NOI2001】食物链
    【HAOI2016】食物链
    luogu P1006 传纸条
    可持久化平衡树
    可持久化并查集
    线段树合并(【POI2011】ROT-Tree Rotations)
    可持久化数组
  • 原文地址:https://www.cnblogs.com/linxmouse/p/8748867.html
Copyright © 2020-2023  润新知