使用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 }
原文地址:https://www.cnblogs.com/linxmouse/p/8748867.html