使用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
  • 0
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
baidu搜索c# HidUsb都是大同小异案例,而且拿下来基本不能用。大都是围绕public static extern int CreateFile(省略众多参数..);发现没有,copy下来测试基本都是用不了的。 原因很简单:windows不允许你用程序随便就去访问硬件设备。所以在此把之前做过的基于C#开发读写HidUsb设备的项目整理成一个简单的小案例,分享给大家,开发环境VS2010。 该案例重点在public static extern SafeFileHandle CreateFile(string lpFileName, uint dwDesiredAccess, int dwShareMode, IntPtr lpSecurityAttributes, int dwCreationDisposition, int dwFlagsAndAttributes, int hTemplateFile); 看着貌似也是用到CreateFile这个函数,其实并不然,注意到没有"SafeFileHandle",这就是重点! 这样windows是允许程序访问外接hidusb设备的。 当然具体如何运用这个函数现在已经不是您应该关心的了,因为我已经为您把它封装成一个类,您只要调用相应的方法就OK. 例:当获取到HidUsb设备信息为:\\?\hid#vid_0e2c&pid_0112#6&1b44c403&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030} 那么: vid为0e2c, pid为:0112 //创建一个HidUsb设备访问实例 UsbHidDevice Device = new UsbHidDevice(vid, pid); //实现数据接收事件 Device.DataReceived += new UsbHidDevice.DataReceivedDelegate(Device_DataReceived); //当HidUsb设备返回信息时触发此事件 void Device_DataReceived(byte[] data){ } //向Hid设备发送数据"0xa0 00 0x12 0x9 0x22" string txt = "0xa0 00 0x12 0x9 0x22"; //把数据转换为字节数组 byte[] data = ConvertHelper.StringToByte(txt2); byte bt = 5; CommandMessage cmdMsg = new CommandMessage(bt, data); Boolean sbool = Device.SendMessage(cmdMsg); //发送数据 Device.Dispose(); //释放所有资源
赋所有源代码,开发工具vs2010 framework3.5 baidu搜索c# HidUsb都是大同小异案例,而且拿下来基本不能用。大都是围绕public static extern int CreateFile(省略众多参数..);发现没有,copy下来测试基本都是用不了的。 原因很简单:windows不允许你用程序随便就去访问硬件设备。所以在此把之前做过的基于C#开发读写HidUsb设备的项目整理成一个简单的小案例,分享给大家,开发环境VS2010。 该案例重点在public static extern SafeFileHandle CreateFile(string lpFileName, uint dwDesiredAccess, int dwShareMode, IntPtr lpSecurityAttributes, int dwCreationDisposition, int dwFlagsAndAttributes, int hTemplateFile); 看着貌似也是用到CreateFile这个函数,其实并不然,注意到没有"SafeFileHandle",这就是重点! 这样windows是允许程序访问外接hidusb设备的。 当然具体如何运用这个函数现在已经不是您应该 关心的了,因为我已经为您把它封装成一个类,您只要调用相应的方法就OK. 例: //第一步:获取HidUsb设备信息 List slist = new List(); UsbHidDevice usbhid = new UsbHidDevice(); usbhid.GetDeviceList(ref slist); //HidUsb设备信息包含在List数据集中 注:当获取到HidUsb设备信息为:\\?\hid#vid_0e2c&pid;_0112#6&1b44c403;&0&0000;#{4d1e55b2-f16f-11cf-88cb-001111000030}, 注意该字符串里的“vid_0e2c”和“pid_0112”部分,那么: vid为0e2c, pid为:0112 //第二步:创建一个HidUsb设备访问实例 UsbHidDevice Device = new UsbHidDevice(vid, pid); //第三步:连接HidUsb设备 Boolean connBool = Device.Connect(); //第四步:实现数据接收事件 Device.DataReceived += new UsbHidDevice.DataReceivedDelegate(Device_DataReceived); //当HidUsb设备返回信息时触发此事件 void Device_DataReceived(byte[] data) { //处理接收到的数据逻辑 } //第五步:向Hid设备发送数据"0xa0 00 0x12 0x9 0x22" string txt = "0xa0 00 0x12 0x9 0x22"; //把数据转换为字节数组 byte[] data = ConvertHelper.StringToByte(txt2); byte bt = 0; CommandMessage cmdMsg = new CommandMessage(bt, data); Boolean sbool = Device.SendMessage(cmdMsg); //发送数据 //第六步:释放所有资源 Device.Dispose();
baidu搜索c# HidUsb都是大同小异案例,而且拿下来基本不能用。大都是围绕public static extern int CreateFile(省略众多参数..);发现没有,copy下来测试基本都是用不了的。 原因很简单:windows不允许你用程序随便就去访问硬件设备。所以在此把之前做过的基于C#开发读写HidUsb设备的项目整理成一个简单的小案例,分享给大家,开发环境VS2010。 该案例重点在public static extern SafeFileHandle CreateFile(string lpFileName, uint dwDesiredAccess, int dwShareMode, IntPtr lpSecurityAttributes, int dwCreationDisposition, int dwFlagsAndAttributes, int hTemplateFile); 看着貌似也是用到CreateFile这个函数,其实并不然,注意到没有"SafeFileHandle",这就是重点! 这样windows是允许程序访问外接hidusb设备的。 当然具体如何运用这个函数现在已经不是您应该关心的了,因为我已经为您把它封装成一个类,您只要调用相应的方法就OK. 例: 获取HidUsb设备信息 List slist = new List(); UsbHidDevice usbhid = new UsbHidDevice(); usbhid.GetDeviceList(ref slist); //HidUsb设备信息包含在List数据集中 当获取到HidUsb设备信息为:\\?\hid#vid_0e2c&pid_0112#6&1b44c403&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030} 那么: vid为0e2c, pid为:0112 //创建一个HidUsb设备访问实例 UsbHidDevice Device = new UsbHidDevice(vid, pid); //实现数据接收事件 Device.DataReceived += new UsbHidDevice.DataReceivedDelegate(Device_DataReceived); //当HidUsb设备返回信息时触发此事件 void Device_DataReceived(byte[] data){ } //向Hid设备发送数据"0xa0 00 0x12 0x9 0x22" string txt = "0xa0 00 0x12 0x9 0x22"; //把数据转换为字节数组 byte[] data = ConvertHelper.StringToByte(txt2); byte bt = 0; CommandMessage cmdMsg = new CommandMessage(bt, data); Boolean sbool = Device.SendMessage(cmdMsg); //发送数据 Device.Dispose(); //释放所有资源

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值