C#枚举出“vid_0451”的hid设备描述符
一、窗体部分
窗体增加一个名称为“list_UsbHID”的listBox控件
窗体部分代码如下:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Management; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using static hid.USBHIDControl; namespace hid { public partial class Form1 : Form { USBHID usbHID = null; public Form1() { InitializeComponent(); usbHID = new USBHID(); foreach (string device in usbHID.GetDeviceList()) { if (device.Contains("vid_0451")) { list_UsbHID.Items.Add(device); } } //usbHID.DataReceived += usbHID_DataReceived; //usbHID.DeviceRemoved += usbHID_DeviceRemoved; } } }
二、新建一个“USBHID.cs”类模块
代码如下:
using System; using System.Collections.Generic; using System.IO; using System.Runtime.InteropServices; using SP_DEVICE_INTERFACE_DATA = hid.WindowsAPI.SP_DEVICE_INTERFACE_DATA; using SP_DEVICE_INTERFACE_DETAIL_DATA = hid.WindowsAPI.SP_DEVICE_INTERFACE_DETAIL_DATA; namespace hid { class USBHIDControl { public class USBHID { //private int outputReportLength; //private int inputReportLength; //private FileStream hidDevice; private const int MAX_USB_DEVICES = 64; WindowsAPI windowsApi = new WindowsAPI(); private List<String> deviceList = new List<string>(); public List<String> GetDeviceList() { return deviceList; } public USBHID() { GetDeviceList(ref deviceList); } /// <summary> /// 获取所有连接HID的设备 /// </summary> /// <param name="deviceList">返回所有连接HID的设备</param> private void GetDeviceList(ref List<string> deviceList) { Guid HIDGuid = Guid.Empty; windowsApi.GetDeviceGuid(ref HIDGuid);//获取HID的全局GUID IntPtr HIDInfoSet = windowsApi.GetClassDevOfHandle(HIDGuid);//获取包含所有HID接口信息集合的句柄 if (HIDInfoSet != IntPtr.Zero) { SP_DEVICE_INTERFACE_DATA interfaceInfo = new SP_DEVICE_INTERFACE_DATA(); interfaceInfo.cbSize = Marshal.SizeOf(interfaceInfo); //检测集合的每个接口 for (uint index = 0; index < MAX_USB_DEVICES; index++) { //获取接口信息 if (!windowsApi.GetEnumDeviceInterfaces(HIDInfoSet, ref HIDGuid, index, ref interfaceInfo)) continue; int buffsize = 0; //获取接口详细信息;第一次读取错误,但可取得信息缓冲区的大小 windowsApi.GetDeviceInterfaceDetail(HIDInfoSet, ref interfaceInfo, IntPtr.Zero, ref buffsize); //接受缓冲 IntPtr pDetail = Marshal.AllocHGlobal(buffsize); SP_DEVICE_INTERFACE_DETAIL_DATA detail = new WindowsAPI.SP_DEVICE_INTERFACE_DETAIL_DATA(); detail.cbSize = Marshal.SizeOf(typeof(hid.WindowsAPI.SP_DEVICE_INTERFACE_DETAIL_DATA)); Marshal.StructureToPtr(detail, pDetail, false); if (windowsApi.GetDeviceInterfaceDetail(HIDInfoSet, ref interfaceInfo, pDetail, ref buffsize))//第二次读取接口详细信息 deviceList.Add(Marshal.PtrToStringAuto((IntPtr)((int)pDetail + 4))); Marshal.FreeHGlobal(pDetail); } } //删除设备信息并释放内存 windowsApi.DestroyDeviceInfoList(HIDInfoSet); } } } /// <summary> /// The HIDD_ATTRIBUTES structure contains vendor information about a HIDClass device /// </summary> public struct HIDD_ATTRIBUTES { public int Size; public ushort VendorID; public ushort ProductID; public ushort VersionNumber; } public struct HIDP_CAPS { public ushort Usage; public ushort UsagePage; public ushort InputReportByteLength; public ushort OutputReportByteLength; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 17)] public ushort[] Reserved; public ushort NumberLinkCollectionNodes; public ushort NumberInputButtonCaps; public ushort NumberInputValueCaps; public ushort NumberInputDataIndices; public ushort NumberOutputButtonCaps; public ushort NumberOutputValueCaps; public ushort NumberOutputDataIndices; public ushort NumberFeatureButtonCaps; public ushort NumberFeatureValueCaps; public ushort NumberFeatureDataIndices; } }
三、新建一个名为“USBHIDEnum.cs”的枚举类
代码如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace hid { class USBHIDEnum { /// <summary> /// Flags controlling what is included in the device information set built by SetupDiGetClassDevs /// </summary> public enum DIGCF { DIGCF_DEFAULT = 0x00000001, // only valid with DIGCF_DEVICEINTERFACE DIGCF_PRESENT = 0x00000002, DIGCF_ALLCLASSES = 0x00000004, DIGCF_PROFILE = 0x00000008, DIGCF_DEVICEINTERFACE = 0x00000010 } /// <summary> /// HID STATUS /// </summary> public enum HID_STATUS { SUCCESS, NO_DEVICE, NO_FIND, OPEND, WRITE_FAID, READ_FAID } } }
四、新建一个名为“WindowsAPI.cs”的类
代码如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Runtime.InteropServices; namespace hid { public class WindowsAPI { /// <summary> /// The HidD_GetHidGuid routine returns the device interface GUID for HIDClass devices. /// </summary> /// <param name="HidGuid">a caller-allocated GUID buffer that the routine uses to return the device interface GUID for HIDClass devices.</param> [DllImport("hid.dll")] private static extern void HidD_GetHidGuid(ref Guid HidGuid); /// <summary> /// The SetupDiGetClassDevs function returns a handle to a device information set that contains requested device information elements for a local machine. /// </summary> /// <param name="ClassGuid">GUID for a device setup class or a device interface class. </param> /// <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> /// <param name="HwndParent">A handle of the top-level window to be used for a user interface</param> /// <param name="Flags">A variable that specifies control options that filter the device information elements that are added to the device information set. /// </param> /// <returns>a handle to a device information set </returns> [DllImport("setupapi.dll", SetLastError = true)] private static extern IntPtr SetupDiGetClassDevs(ref Guid ClassGuid, uint Enumerator, IntPtr HwndParent, USBHIDEnum.DIGCF Flags); /// <summary> /// The SetupDiEnumDeviceInterfaces function enumerates the device interfaces that are contained in a device information set. /// </summary> /// <param name="deviceInfoSet">A pointer to a device information set that contains the device interfaces for which to return information</param> /// <param name="deviceInfoData">A pointer to an SP_DEVINFO_DATA structure that specifies a device information element in DeviceInfoSet</param> /// <param name="interfaceClassGuid">a GUID that specifies the device interface class for the requested interface</param> /// <param name="memberIndex">A zero-based index into the list of interfaces in the device information set</param> /// <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> /// <returns></returns> [DllImport("setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)] private static extern Boolean SetupDiEnumDeviceInterfaces(IntPtr deviceInfoSet, IntPtr deviceInfoData, ref Guid interfaceClassGuid, UInt32 memberIndex, ref SP_DEVICE_INTERFACE_DATA deviceInterfaceData); /// <summary> /// SP_DEVICE_INTERFACE_DATA structure defines a device interface in a device information set. /// </summary> public struct SP_DEVICE_INTERFACE_DATA { public int cbSize; public Guid interfaceClassGuid; public int flags; public int reserved; } /// <summary> /// The SetupDiGetDeviceInterfaceDetail function returns details about a device interface. /// </summary> /// <param name="deviceInfoSet">A pointer to the device information set that contains the interface for which to retrieve details</param> /// <param name="deviceInterfaceData">A pointer to an SP_DEVICE_INTERFACE_DATA structure that specifies the interface in DeviceInfoSet for which to retrieve details</param> /// <param name="deviceInterfaceDetailData">A pointer to an SP_DEVICE_INTERFACE_DETAIL_DATA structure to receive information about the specified interface</param> /// <param name="deviceInterfaceDetailDataSize">The size of the DeviceInterfaceDetailData buffer</param> /// <param name="requiredSize">A pointer to a variable that receives the required size of the DeviceInterfaceDetailData buffer</param> /// <param name="deviceInfoData">A pointer buffer to receive information about the device that supports the requested interface</param> /// <returns></returns> [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)] private static extern bool SetupDiGetDeviceInterfaceDetail(IntPtr deviceInfoSet, ref SP_DEVICE_INTERFACE_DATA deviceInterfaceData, IntPtr deviceInterfaceDetailData, int deviceInterfaceDetailDataSize, ref int requiredSize, SP_DEVINFO_DATA deviceInfoData); /// <summary> /// SP_DEVINFO_DATA structure defines a device instance that is a member of a device information set. /// </summary> [StructLayout(LayoutKind.Sequential)] public class SP_DEVINFO_DATA { public int cbSize = Marshal.SizeOf(typeof(SP_DEVINFO_DATA)); public Guid classGuid = Guid.Empty; // temp public int devInst = 0; // dumy public int reserved = 0; } /// <summary> /// SP_DEVICE_INTERFACE_DETAIL_DATA structure contains the path for a device interface. /// </summary> [StructLayout(LayoutKind.Sequential, Pack = 2)] internal struct SP_DEVICE_INTERFACE_DETAIL_DATA { internal int cbSize; internal short devicePath; } /// <summary> /// The SetupDiDestroyDeviceInfoList function deletes a device information set and frees all associated memory. /// </summary> /// <param name="DeviceInfoSet">A handle to the device information set to delete.</param> /// <returns>returns TRUE if it is successful. Otherwise, it returns FALSE </returns> [DllImport("setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)] private static extern Boolean SetupDiDestroyDeviceInfoList(IntPtr deviceInfoSet); /// <summary> /// This function creates, opens, or truncates a file, COM port, device, service, or console. /// </summary> /// <param name="fileName">a null-terminated string that specifies the name of the object</param> /// <param name="desiredAccess">Type of access to the object</param> /// <param name="shareMode">Share mode for object</param> /// <param name="securityAttributes">Ignored; set to NULL</param> /// <param name="creationDisposition">Action to take on files that exist, and which action to take when files do not exist</param> /// <param name="flagsAndAttributes">File attributes and flags for the file</param> /// <param name="templateFile">Ignored</param> /// <returns>An open handle to the specified file indicates success</returns> [DllImport("kernel32.dll", SetLastError = true)] //private static extern IntPtr CreateFile(string fileName, uint desiredAccess, uint shareMode, uint securityAttributes, uint creationDisposition, uint flagsAndAttributes, uint templateFile); static extern IntPtr CreateFile( string FileName, // 文件名 uint DesiredAccess, // 访问模式 uint ShareMode, // 共享模式 uint SecurityAttributes, // 安全属性 uint CreationDisposition, // 如何创建 uint FlagsAndAttributes, // 文件属性 int hTemplateFile // 模板文件的句柄 ); /// <summary> /// The HidD_GetAttributes routine returns the attributes of a specified top-level collection. /// </summary> /// <param name="HidDeviceObject">Specifies an open handle to a top-level collection</param> /// <param name="Attributes">a caller-allocated HIDD_ATTRIBUTES structure that returns the attributes of the collection specified by HidDeviceObject</param> /// <returns></returns> [DllImport("hid.dll")] private static extern Boolean HidD_GetAttributes(IntPtr hidDeviceObject, out HIDD_ATTRIBUTES attributes); /// <summary> /// The HidD_GetPreparsedData routine returns a top-level collection's preparsed data. /// </summary> /// <param name="hidDeviceObject">Specifies an open handle to a top-level collection. </param> /// <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> /// <returns>HidD_GetPreparsedData returns TRUE if it succeeds; otherwise, it returns FALSE.</returns> [DllImport("hid.dll")] private static extern Boolean HidD_GetPreparsedData(IntPtr hidDeviceObject, out IntPtr PreparsedData); [DllImport("hid.dll")] private static extern uint HidP_GetCaps(IntPtr PreparsedData, out HIDP_CAPS Capabilities); [DllImport("hid.dll")] private static extern Boolean HidD_FreePreparsedData(IntPtr PreparsedData); /// <summary> /// get device guid /// </summary> /// <param name="HIDGuid"></param> internal void GetDeviceGuid(ref Guid HIDGuid) { HidD_GetHidGuid(ref HIDGuid); } /// <summary> /// get IntPtr about all of Devs /// </summary> /// <param name="HIDGuid"></param> /// <returns></returns> internal IntPtr GetClassDevOfHandle(Guid HIDGuid) { return SetupDiGetClassDevs(ref HIDGuid, 0, IntPtr.Zero, USBHIDEnum.DIGCF.DIGCF_PRESENT | USBHIDEnum.DIGCF.DIGCF_DEVICEINTERFACE); } /// <summary> /// get interfaces information /// </summary> /// <param name="HIDInfoSet"></param> /// <param name="HIDGuid"></param> /// <param name="index"></param> /// <param name="interfaceInfo"></param> /// <returns></returns> internal bool GetEnumDeviceInterfaces(IntPtr HIDInfoSet, ref Guid HIDGuid, uint index, ref SP_DEVICE_INTERFACE_DATA interfaceInfo) { return SetupDiEnumDeviceInterfaces(HIDInfoSet, IntPtr.Zero, ref HIDGuid, index, ref interfaceInfo); } /// <summary> /// get interface detail information /// </summary> /// <param name="HIDInfoSet"></param> /// <param name="interfaceInfo"></param> /// <param name="buffsize"></param> /// <param name="buffsize_2"></param> internal bool GetDeviceInterfaceDetail(IntPtr HIDInfoSet, ref SP_DEVICE_INTERFACE_DATA interfaceInfo, IntPtr pDetail, ref int buffsize) { return SetupDiGetDeviceInterfaceDetail(HIDInfoSet, ref interfaceInfo, pDetail, buffsize, ref buffsize, null); } /// <summary> /// Destroy Device information list /// </summary> /// <param name="HIDInfoSet"></param> internal void DestroyDeviceInfoList(IntPtr HIDInfoSet) { SetupDiDestroyDeviceInfoList(HIDInfoSet); } internal IntPtr CreateDeviceFile(string device) { //return new IntPtr (); return CreateFile(device, DESIREDACCESS.GENERIC_READ | DESIREDACCESS.GENERIC_WRITE, 0, 0, CREATIONDISPOSITION.OPEN_EXISTING, FLAGSANDATTRIBUTES.FILE_FLAG_OVERLAPPED, 0); } /// <summary> /// File attributes and flags for the file. /// </summary> static class FLAGSANDATTRIBUTES { public const uint FILE_FLAG_WRITE_THROUGH = 0x80000000; public const uint FILE_FLAG_OVERLAPPED = 0x40000000; public const uint FILE_FLAG_NO_BUFFERING = 0x20000000; public const uint FILE_FLAG_RANDOM_ACCESS = 0x10000000; public const uint FILE_FLAG_SEQUENTIAL_SCAN = 0x08000000; public const uint FILE_FLAG_DELETE_ON_CLOSE = 0x04000000; public const uint FILE_FLAG_BACKUP_SEMANTICS = 0x02000000; public const uint FILE_FLAG_POSIX_SEMANTICS = 0x01000000; public const uint FILE_FLAG_OPEN_REPARSE_POINT = 0x00200000; public const uint FILE_FLAG_OPEN_NO_RECALL = 0x00100000; public const uint FILE_FLAG_FIRST_PIPE_INSTANCE = 0x00080000; } /// <summary> /// Action to take on files that exist, and which action to take when files do not exist. /// </summary> static class CREATIONDISPOSITION { public const uint CREATE_NEW = 1; public const uint CREATE_ALWAYS = 2; public const uint OPEN_EXISTING = 3; public const uint OPEN_ALWAYS = 4; public const uint TRUNCATE_EXISTING = 5; } /// <summary> /// Type of access to the object. ///</summary> static class DESIREDACCESS { public const uint GENERIC_READ = 0x80000000; public const uint GENERIC_WRITE = 0x40000000; public const uint GENERIC_EXECUTE = 0x20000000; public const uint GENERIC_ALL = 0x10000000; } /// <summary> /// Get Device Attribute /// </summary> /// <param name="device"></param> /// <param name="attributes"></param> internal void GETDeviceAttribute(IntPtr device, out HIDD_ATTRIBUTES attributes) { HidD_GetAttributes(device, out attributes); } /// <summary> /// Get Preparse Data /// </summary> /// <param name="device"></param> /// <param name="preparseData"></param> internal void GetPreparseData(IntPtr device, out IntPtr preparseData) { HidD_GetPreparsedData(device, out preparseData); } /// <summary> /// Get Caps /// </summary> /// <param name="preparseData"></param> /// <param name="caps"></param> internal void GetCaps(IntPtr preparseData, out HIDP_CAPS caps) { HidP_GetCaps(preparseData, out caps); } /// <summary> /// free preparse data /// </summary> /// <param name="preparseData"></param> internal void FreePreparseData(IntPtr preparseData) { HidD_FreePreparsedData(preparseData); } } }
整体结构如图:
运行效果如下:
由于我只需要枚举出包含"vid_0451"的设备描述符,所以代码部分我做了很多简化。
如果需要全部hid设备描述符,把下方代码的if去掉即可。
foreach (string device in usbHID.GetDeviceList())
{
if (device.Contains("vid_0451"))
{
list_UsbHID.Items.Add(device);
}
}
为了这个功能,折磨了2天,摸索了2天,做个学习记录把,可能下次还会用到呢。