本文转载于: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 }
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 }
调用如下:
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 }