(一)DeviceIoControl的PInvoke
/* ---------------------------------------------------------- 文件名称:DeviceIoControl.cs 作者:秦建辉 MSN:splashcn@msn.com QQ:36748897 博客:http://blog.csdn.net/jhqin 开发环境: Visual Studio V2010 .NET Framework 4 Client Profile 版本历史: V1.0 2011年10月10日 实现对DeviceIoControl接口的PInvoke 参考资料: http://www.pinvoke.net/ ------------------------------------------------------------ */ using System; using System.Runtime.InteropServices; namespace Splash.IO.PORTS { #region ENUM public enum USB_HUB_NODE : uint { UsbHub, UsbMIParent } public enum USB_CONNECTION_STATUS { NoDeviceConnected, DeviceConnected, DeviceFailedEnumeration, DeviceGeneralFailure, DeviceCausedOvercurrent, DeviceNotEnoughPower, DeviceNotEnoughBandwidth, DeviceHubNestedTooDeeply, DeviceInLegacyHub } public enum USB_DEVICE_SPEED : byte { UsbLowSpeed, // 低速USB 1.1 UsbFullSpeed, // 全速USB 1.1 UsbHighSpeed, // 高速USB 2.0 UsbSuperSpeed // 极速USB 3.0 } #endregion public partial class USB { internal const Int32 IOCTL_GET_HCD_DRIVERKEY_NAME = 0x220424; internal const Int32 IOCTL_USB_GET_ROOT_HUB_NAME = 0x220408; internal const Int32 IOCTL_USB_GET_NODE_CONNECTION_NAME = 0x220414; internal const Int32 IOCTL_USB_GET_NODE_INFORMATION = 0x220408; internal const Int32 IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX = 0x220448; internal const Int32 IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION = 0x220410; internal const Int32 MAXIMUM_USB_STRING_LENGTH = 255; internal const Int32 USB_STRING_DESCRIPTOR_TYPE = 3; [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] internal struct USB_HCD_DRIVERKEY_NAME { public Int32 ActualLength; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] public String Name; } #region USB_NODE_INFORMATION [StructLayout(LayoutKind.Sequential, Pack = 1)] internal struct USB_HUB_DESCRIPTOR { public Byte bDescriptorLength; public Byte bDescriptorType; // 描述符类型:0x29 public Byte bNumberOfPorts; // 支持的下游端口数目 public Int16 wHubCharacteristics; // 特征描述 public Byte bPowerOnToPowerGood; // 从端口加电到端口正常工作的时间间隔(以2ms为单位) public Byte bHubControlCurrent; // 设备所需最大电流 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] public Byte[] bRemoveAndPowerMask; // 指示连接在集线器端口的设备是否可移走 } [StructLayout(LayoutKind.Sequential)] internal struct USB_HUB_INFORMATION { public USB_HUB_DESCRIPTOR HubDescriptor; public Byte HubIsBusPowered; } [StructLayout(LayoutKind.Sequential)] internal struct USB_MI_PARENT_INFORMATION { public Int32 NumberOfInterfaces; }; [StructLayout(LayoutKind.Explicit)] internal struct UsbNodeUnion { [FieldOffset(0)] public USB_HUB_INFORMATION HubInformation; [FieldOffset(0)] public USB_MI_PARENT_INFORMATION MiParentInformation; } [StructLayout(LayoutKind.Sequential)] internal struct USB_NODE_INFORMATION { public USB_HUB_NODE NodeType; public UsbNodeUnion u; } #endregion #region USB_NODE_CONNECTION_INFORMATION [StructLayout(LayoutKind.Sequential, Pack = 1)] internal struct USB_DEVICE_DESCRIPTOR { public Byte bLength; public Byte bDescriptorType; public UInt16 bcdUSB; public Byte bDeviceClass; public Byte bDeviceSubClass; public Byte bDeviceProtocol; public Byte bMaxPacketSize0; public UInt16 idVendor; public UInt16 idProduct; public UInt16 bcdDevice; public Byte iManufacturer; public Byte iProduct; public Byte iSerialNumber; public Byte bNumConfigurations; } [StructLayout(LayoutKind.Sequential, Pack = 1)] internal struct USB_ENDPOINT_DESCRIPTOR { public Byte bLength; public Byte bDescriptorType; public Byte bEndpointAddress; public Byte bmAttributes; public UInt16 wMaxPacketSize; public Byte bInterval; } [StructLayout(LayoutKind.Sequential, Pack = 1)] internal struct USB_PIPE_INFO { public USB_ENDPOINT_DESCRIPTOR EndpointDescriptor; public UInt32 ScheduleOffset; } [StructLayout(LayoutKind.Sequential, Pack = 1)] internal struct USB_NODE_CONNECTION_INFORMATION_EX { public Int32 ConnectionIndex; public USB_DEVICE_DESCRIPTOR DeviceDescriptor; public Byte CurrentConfigurationValue; public Byte Speed; public Byte DeviceIsHub; public Int16 DeviceAddress; public Int32 NumberOfOpenPipes; public USB_CONNECTION_STATUS ConnectionStatus; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] public USB_PIPE_INFO[] PipeList; } #endregion #region USB_DESCRIPTOR_REQUEST [StructLayout(LayoutKind.Sequential)] internal struct USB_SETUP_PACKET { public Byte bmRequest; public Byte bRequest; public UInt16 wValue; public UInt16 wIndex; public UInt16 wLength; } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] internal struct USB_STRING_DESCRIPTOR { public Byte bLength; public Byte bDescriptorType; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAXIMUM_USB_STRING_LENGTH)] public String bString; } [StructLayout(LayoutKind.Sequential)] internal struct USB_DESCRIPTOR_REQUEST { public Int32 ConnectionIndex; public USB_SETUP_PACKET SetupPacket; public USB_STRING_DESCRIPTOR Data; } #endregion #region USB_NODE_CONNECTION_DRIVERKEY_NAME [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] internal struct USB_NODE_CONNECTION_DRIVERKEY_NAME { public Int32 ConnectionIndex; public Int32 ActualLength; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAXIMUM_USB_STRING_LENGTH)] public String DriverKeyName; } #endregion #region DeviceIoControl [DllImport("kernel32.dll", CharSet = CharSet.Ansi, SetLastError = true)] internal static extern Boolean DeviceIoControl( IntPtr hFile, Int32 dwIoControlCode, IntPtr lpInBuffer, Int32 nInBufferSize, ref USB_HCD_DRIVERKEY_NAME lpOutBuffer, Int32 nOutBufferSize, out Int32 nBytesReturned, IntPtr lpOverlapped ); [DllImport("kernel32.dll", CharSet = CharSet.Ansi, SetLastError = true)] internal static extern Boolean DeviceIoControl( IntPtr hFile, Int32 dwIoControlCode, ref USB_NODE_INFORMATION lpInBuffer, Int32 nInBufferSize, ref USB_NODE_INFORMATION lpOutBuffer, Int32 nOutBufferSize, out Int32 lpBytesReturned, IntPtr lpOverlapped ); [DllImport("kernel32.dll", CharSet = CharSet.Ansi, SetLastError = true)] internal static extern Boolean DeviceIoControl( IntPtr hFile, Int32 dwIoControlCode, ref USB_NODE_CONNECTION_INFORMATION_EX lpInBuffer, Int32 nInBufferSize, ref USB_NODE_CONNECTION_INFORMATION_EX lpOutBuffer, Int32 nOutBufferSize, out Int32 lpBytesReturned, IntPtr lpOverlapped ); [DllImport("kernel32.dll", CharSet = CharSet.Ansi, SetLastError = true)] internal static extern Boolean DeviceIoControl( IntPtr hFile, Int32 dwIoControlCode, ref USB_DESCRIPTOR_REQUEST lpInBuffer, Int32 nInBufferSize, ref USB_DESCRIPTOR_REQUEST lpOutBuffer, Int32 nOutBufferSize, out Int32 lpBytesReturned, IntPtr lpOverlapped ); [DllImport("kernel32.dll", CharSet = CharSet.Ansi, SetLastError = true)] internal static extern Boolean DeviceIoControl( IntPtr hFile, Int32 dwIoControlCode, ref USB_NODE_CONNECTION_DRIVERKEY_NAME lpInBuffer, Int32 nInBufferSize, ref USB_NODE_CONNECTION_DRIVERKEY_NAME lpOutBuffer, Int32 nOutBufferSize, out Int32 lpBytesReturned, IntPtr lpOverlapped ); #endregion } }
(二)设备枚举API
/* ---------------------------------------------------------- 文件名称:WDKUsbEnum.cs 作者:秦建辉 MSN:splashcn@msn.com QQ:36748897 博客:http://blog.csdn.net/jhqin 开发环境: Visual Studio V2010 .NET Framework 4 Client Profile 版本历史: V1.0 2011年10月10日 基于WDK枚举USB设备 ------------------------------------------------------------ */ using System; using System.Collections.Generic; using System.Management; using System.Runtime.InteropServices; using System.Text; namespace Splash.IO.PORTS { /// <summary> /// USB主控制器信息 /// </summary> public struct HostControllerInfo { public String PNPDeviceID; // 设备ID public String Name; // 设备名称 } /// <summary> /// USB Hub信息 /// </summary> public struct UsbHubInfo { public String PNPDeviceID; // 设备ID public String Name; // 设备名称 public String Status; // 设备状态 } /// <summary> /// USB HUB节点信息 /// </summary> public struct UsbNodeInformation { public String DevicePath; // 设备路径 public String PNPDeviceID; // 设备ID public String Name; // 设备名称 public USB_HUB_NODE NodeType; // 节点类型 // USB_HUB_INFORMATION public Boolean HubIsBusPowered; // 供电方式:true-总线供电 false-独立供电 public Int32 NumberOfPorts; // 端口数 public Int16 HubCharacteristics; // 特征描述 public Byte PowerOnToPowerGood; // 从端口加电到端口正常工作的时间间隔(以2ms为单位) public Byte HubControlCurrent; // 设备所需最大电流 // USB_MI_PARENT_INFORMATION public Int32 NumberOfInterfaces; // 接口数 } /// <summary> /// USB设备描述符 /// </summary> public struct UsbDeviceDescriptor { public Byte bDescriptorType; // 描述符类型 USB_DEVICE_DESCRIPTOR_TYPE public String UsbVersion; // USB规格版本号 public Byte bDeviceClass; // 设备类型 public Byte bDeviceSubClass; // 设备子类型 public Byte bDeviceProtocol; // 设备协议 public Byte bMaxPacketSize0; // 最大封包大小 public UInt16 idVendor; // VID public UInt16 idProduct; // PID public String DeviceVersion; // 设备版本号 public String Manufacturer; // 制造商 public String Product; // 产品描述 public String SerialNumber; // 序列号 public Byte bNumConfigurations; // 配置总数 } /// <summary> /// USB管道信息 /// </summary> public struct UsbPipeInfo { public UInt32 ScheduleOffset; public Byte bDescriptorType; public Byte bEndpointAddress; public Byte bmAttributes; public UInt16 wMaxPacketSize; public Byte bInterval; } /// <summary> /// USB节点连接信息 /// </summary> public struct UsbNodeConnectionInformation { public String DevicePath; // 设备路径 public Int32 ConnectionIndex; // 端口号 public UsbDeviceDescriptor DeviceDescriptor; public Byte CurrentConfigurationValue; // 当前设备配置 public Byte Speed; // 设备速度 public Boolean DeviceIsHub; // 是否是集线器 public Int32 DeviceAddress; // 设备地址 public Int32 NumberOfOpenPipes; // 管道数 public USB_CONNECTION_STATUS ConnectionStatus; // 连接状态 public List<UsbPipeInfo> PipeList; // 管道信息 } /// <summary> /// USB设备枚举 /// </summary> public partial class USB { #region HostController /// <summary> /// USB主控制器 /// </summary> public static HostControllerInfo[] AllHostControllers { get { List<HostControllerInfo> HostControllers = new List<HostControllerInfo>(); // 获取USB控制器及其相关联的设备实体 ManagementObjectCollection MOC = new ManagementObjectSearcher("SELECT * FROM Win32_USBController").Get(); if (MOC != null) { foreach (ManagementObject MO in MOC) { HostControllerInfo Element; Element.PNPDeviceID = MO["PNPDeviceID"] as String; // 设备ID Element.Name = MO["Name"] as String; // 设备描述 HostControllers.Add(Element); } } if (HostControllers.Count == 0) return null; else return HostControllers.ToArray(); } } /// <summary> /// 获取驱动键名 /// </summary> /// <param name="PNPDeviceID">USB主控制器设备ID</param> /// <returns>获取设备驱动在注册表HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class下的路径</returns> public static String GetHcdDriverKeyName(String PNPDeviceID) { if (String.IsNullOrEmpty(PNPDeviceID)) return null; // 打开设备 IntPtr hHCDev = Kernel32.CreateFile( "\\\\.\\" + PNPDeviceID.Replace(‘\\‘, ‘#‘) + "#{3ABF6F2D-71C4-462A-8A92-1E6861E6AF27}", NativeFileAccess.GENERIC_WRITE, NativeFileShare.FILE_SHARE_WRITE, IntPtr.Zero, NativeFileMode.OPEN_EXISTING, IntPtr.Zero, IntPtr.Zero); if (hHCDev == Kernel32.INVALID_HANDLE_VALUE) return null; // 获取驱动键名 Int32 nBytesReturned; USB_HCD_DRIVERKEY_NAME Buffer = new USB_HCD_DRIVERKEY_NAME(); Boolean Status = DeviceIoControl(hHCDev, IOCTL_GET_HCD_DRIVERKEY_NAME, IntPtr.Zero, 0, ref Buffer, Marshal.SizeOf(Buffer), out nBytesReturned, IntPtr.Zero); // 关闭设备 Kernel32.CloseHandle(hHCDev); return Status ? Buffer.Name : null; } #endregion #region USBHUB /// <summary> /// USB Hub信息集合 /// </summary> public static UsbHubInfo[] AllUsbHubs { get { List<UsbHubInfo> UsbHubs = new List<UsbHubInfo>(); // 获取USB控制器及其相关联的设备实体 ManagementObjectCollection MOC = new ManagementObjectSearcher("SELECT * FROM Win32_USBHub").Get(); if (MOC != null) { foreach (ManagementObject MO in MOC) { UsbHubInfo Element; Element.PNPDeviceID = MO["PNPDeviceID"] as String; // 设备ID Element.Name = MO["Name"] as String; // 设备描述 Element.Status = MO["Status"] as String; // 设备状态 UsbHubs.Add(Element); } } if (UsbHubs.Count == 0) return null; else return UsbHubs.ToArray(); } } /// <summary> /// USB ROOT HUB设备路径 /// </summary> /// <param name="PNPDeviceID">USB主控制器设备ID</param> /// <returns>USB ROOT HUB设备路径</returns> public static String GetUsbRootHubPath(String PNPDeviceID) { if (String.IsNullOrEmpty(PNPDeviceID)) return null; // 打开设备 IntPtr hHCDev = Kernel32.CreateFile( "\\\\.\\" + PNPDeviceID.Replace(‘\\‘, ‘#‘) + "#{3ABF6F2D-71C4-462A-8A92-1E6861E6AF27}", NativeFileAccess.GENERIC_WRITE, NativeFileShare.FILE_SHARE_WRITE, IntPtr.Zero, NativeFileMode.OPEN_EXISTING, IntPtr.Zero, IntPtr.Zero); if (hHCDev == Kernel32.INVALID_HANDLE_VALUE) return null; // 获取USB ROOT HUB名称 Int32 nBytesReturned; USB_HCD_DRIVERKEY_NAME Buffer = new USB_HCD_DRIVERKEY_NAME(); Boolean Status = DeviceIoControl(hHCDev, IOCTL_USB_GET_ROOT_HUB_NAME, IntPtr.Zero, 0, ref Buffer, Marshal.SizeOf(Buffer), out nBytesReturned, IntPtr.Zero); // 关闭设备 Kernel32.CloseHandle(hHCDev); return Status ? Buffer.Name : null; } /// <summary> /// USB HUB设备名称 /// </summary> /// <param name="DevicePath">设备路径</param> /// <returns>设备名称</returns> public static String GetUsbHubName(String DevicePath) { if (String.IsNullOrEmpty(DevicePath)) return null; // 从设备路径中提取设备ID String DeviceID = DevicePath.Substring(0, DevicePath.LastIndexOf(‘#‘)).Replace(‘#‘, ‘_‘); // 从Win32_USBHub获取设备描述 ManagementObjectCollection MOC = new ManagementObjectSearcher("SELECT * FROM Win32_USBHub WHERE DeviceID LIKE ‘" + DeviceID + "‘").Get(); if (MOC != null) { foreach (ManagementObject MO in MOC) { return MO["Name"] as String; } } return null; } /// <summary> /// 获取USB HUB节点信息 /// </summary> /// <param name="DevicePath">USB HUB设备路径</param> /// <returns>节点信息</returns> public static UsbNodeInformation[] GetUsbNodeInformation(String DevicePath) { if (String.IsNullOrEmpty(DevicePath)) return null; // 打开设备文件 IntPtr hHubDevice = Kernel32.CreateFile( "\\\\.\\" + DevicePath, NativeFileAccess.GENERIC_WRITE, NativeFileShare.FILE_SHARE_WRITE, IntPtr.Zero, NativeFileMode.OPEN_EXISTING, IntPtr.Zero, IntPtr.Zero); if (hHubDevice == Kernel32.INVALID_HANDLE_VALUE) return null; // 查询节点信息 Int32 nBytesReturned; USB_NODE_INFORMATION Buffer = new USB_NODE_INFORMATION(); Boolean Status = DeviceIoControl(hHubDevice, IOCTL_USB_GET_NODE_INFORMATION, ref Buffer, Marshal.SizeOf(Buffer), ref Buffer, Marshal.SizeOf(Buffer), out nBytesReturned, IntPtr.Zero); // 关闭设备文件 Kernel32.CloseHandle(hHubDevice); if (!Status) return null; UsbNodeInformation Node = new UsbNodeInformation(); Node.NodeType = Buffer.NodeType; // 节点类型 Node.PNPDeviceID = DevicePath.Substring(0, DevicePath.LastIndexOf(‘#‘)).Replace(‘#‘, ‘\\‘); // 设备ID Node.DevicePath = DevicePath; // 设备路径 Node.Name = GetUsbHubName(DevicePath); // 设备名称 if (Buffer.NodeType == USB_HUB_NODE.UsbHub) { Node.NumberOfPorts = Buffer.u.HubInformation.HubDescriptor.bNumberOfPorts; // 端口数 Node.HubIsBusPowered = Convert.ToBoolean(Buffer.u.HubInformation.HubIsBusPowered); // 供电方式 Node.HubCharacteristics = Buffer.u.HubInformation.HubDescriptor.wHubCharacteristics; Node.PowerOnToPowerGood = Buffer.u.HubInformation.HubDescriptor.bPowerOnToPowerGood; Node.HubControlCurrent = Buffer.u.HubInformation.HubDescriptor.bHubControlCurrent; } else { Node.NumberOfInterfaces = Buffer.u.MiParentInformation.NumberOfInterfaces; // 接口数 } return new UsbNodeInformation[1] { Node }; } #endregion #region NODECONNECTION /// <summary> /// 获取USB节点连接信息 /// </summary> /// <param name="DevicePath">设备路径</param> /// <param name="NumberOfPorts">端口总数</param> /// <returns>USB节点信息连接信息集合</returns> public static UsbNodeConnectionInformation[] GetUsbNodeConnectionInformation(String DevicePath, Int32 NumberOfPorts) { if (String.IsNullOrEmpty(DevicePath)) return null; // 打开设备文件 IntPtr hHubDevice = Kernel32.CreateFile( "\\\\.\\" + DevicePath, NativeFileAccess.GENERIC_WRITE, NativeFileShare.FILE_SHARE_WRITE, IntPtr.Zero, NativeFileMode.OPEN_EXISTING, IntPtr.Zero, IntPtr.Zero); if (hHubDevice == Kernel32.INVALID_HANDLE_VALUE) return null; List<UsbNodeConnectionInformation> NodeCollection = new List<UsbNodeConnectionInformation>(); // 枚举端口 USB_NODE_CONNECTION_INFORMATION_EX Buffer = new USB_NODE_CONNECTION_INFORMATION_EX(); for (Int32 ConnectionIndex = 1; ConnectionIndex <= NumberOfPorts; ConnectionIndex++) { // 查询节点信息 Int32 nBytesReturned; Buffer.ConnectionIndex = ConnectionIndex; Boolean Status = DeviceIoControl(hHubDevice, IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX, ref Buffer, Marshal.SizeOf(Buffer), ref Buffer, Marshal.SizeOf(Buffer), out nBytesReturned, IntPtr.Zero); if (Status) { // 确定语言ID UInt16 LanguageID = SelectLanguageID(hHubDevice, ConnectionIndex); // 提取信息 UsbNodeConnectionInformation Node = new UsbNodeConnectionInformation(); Node.DevicePath = DevicePath; Node.ConnectionIndex = Buffer.ConnectionIndex; Node.ConnectionStatus = Buffer.ConnectionStatus; if (Buffer.ConnectionStatus == USB_CONNECTION_STATUS.DeviceConnected) { Node.CurrentConfigurationValue = Buffer.CurrentConfigurationValue; Node.Speed = Buffer.Speed; Node.DeviceIsHub = Convert.ToBoolean(Buffer.DeviceIsHub); Node.DeviceAddress = Buffer.DeviceAddress; Node.NumberOfOpenPipes = Buffer.NumberOfOpenPipes; // 设备描述符 Node.DeviceDescriptor.bDescriptorType = Buffer.DeviceDescriptor.bDescriptorType; Node.DeviceDescriptor.bDeviceClass = Buffer.DeviceDescriptor.bDeviceClass; Node.DeviceDescriptor.bDeviceSubClass = Buffer.DeviceDescriptor.bDeviceSubClass; Node.DeviceDescriptor.bDeviceProtocol = Buffer.DeviceDescriptor.bDeviceProtocol; Node.DeviceDescriptor.UsbVersion = BcdVersionToString(Buffer.DeviceDescriptor.bcdUSB); // USB版本号 Node.DeviceDescriptor.DeviceVersion = BcdVersionToString(Buffer.DeviceDescriptor.bcdDevice); // 设备版本号 Node.DeviceDescriptor.idVendor = Buffer.DeviceDescriptor.idVendor; // 厂商标识 Node.DeviceDescriptor.idProduct = Buffer.DeviceDescriptor.idProduct; // 产品标识 if (LanguageID != 0) { if (Buffer.DeviceDescriptor.iSerialNumber != 0) { // 序列号 Node.DeviceDescriptor.SerialNumber = GetStringDescriptor(hHubDevice, Buffer.ConnectionIndex, Buffer.DeviceDescriptor.iSerialNumber, LanguageID); } if (Buffer.DeviceDescriptor.iManufacturer != 0) { // 制造商名称 Node.DeviceDescriptor.Manufacturer = GetStringDescriptor(hHubDevice, Buffer.ConnectionIndex, Buffer.DeviceDescriptor.iManufacturer, LanguageID); } if (Buffer.DeviceDescriptor.iProduct != 0) { // 产品名称 Node.DeviceDescriptor.Product = GetStringDescriptor(hHubDevice, Buffer.ConnectionIndex, Buffer.DeviceDescriptor.iProduct, LanguageID); } } Node.DeviceDescriptor.bMaxPacketSize0 = Buffer.DeviceDescriptor.bMaxPacketSize0; Node.DeviceDescriptor.bNumConfigurations = Buffer.DeviceDescriptor.bNumConfigurations; // 管道信息 Node.PipeList = new List<UsbPipeInfo>(); for (Int32 PipeIndex = 0; PipeIndex < Buffer.NumberOfOpenPipes; PipeIndex++) { UsbPipeInfo PipeInfo; PipeInfo.ScheduleOffset = Buffer.PipeList[PipeIndex].ScheduleOffset; PipeInfo.bDescriptorType = Buffer.PipeList[PipeIndex].EndpointDescriptor.bDescriptorType; PipeInfo.bEndpointAddress = Buffer.PipeList[PipeIndex].EndpointDescriptor.bEndpointAddress; PipeInfo.bmAttributes = Buffer.PipeList[PipeIndex].EndpointDescriptor.bmAttributes; PipeInfo.wMaxPacketSize = Buffer.PipeList[PipeIndex].EndpointDescriptor.wMaxPacketSize; PipeInfo.bInterval = Buffer.PipeList[PipeIndex].EndpointDescriptor.bInterval; Node.PipeList.Add(PipeInfo); } } NodeCollection.Add(Node); } } // 关闭设备文件 Kernel32.CloseHandle(hHubDevice); // 返回结果 if (NodeCollection.Count == 0) return null; else return NodeCollection.ToArray(); } /// <summary> /// 获取字符串描述符 /// </summary> /// <param name="hHubDevice">USB Hub设备句柄</param> /// <param name="ConnectionIndex">连接索引号</param> /// <param name="DescriptorIndex">描述符索引号</param> /// <param name="LanguageID">语言ID</param> /// <returns>字符串描述符</returns> public static String GetStringDescriptor(IntPtr hHubDevice, Int32 ConnectionIndex, Byte DescriptorIndex, UInt16 LanguageID) { USB_DESCRIPTOR_REQUEST Buffer = new USB_DESCRIPTOR_REQUEST(); Buffer.ConnectionIndex = ConnectionIndex; Buffer.SetupPacket.wValue = (UInt16)((USB_STRING_DESCRIPTOR_TYPE << 8) | DescriptorIndex); Buffer.SetupPacket.wIndex = LanguageID; Buffer.SetupPacket.wLength = MAXIMUM_USB_STRING_LENGTH; Int32 nBytesReturned; Boolean Status = DeviceIoControl(hHubDevice, IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, ref Buffer, Marshal.SizeOf(Buffer), ref Buffer, Marshal.SizeOf(Buffer), out nBytesReturned, IntPtr.Zero); if (Status) return Buffer.Data.bString; else return null; } /// <summary> /// 选择语言ID /// </summary> /// <param name="hHubDevice">USB Hub设备句柄</param> /// <param name="ConnectionIndex">连接索引号</param> /// <returns></returns> public static UInt16 SelectLanguageID(IntPtr hHubDevice, Int32 ConnectionIndex) { // 获取支持的语言列表 String SupportedLanguagesString = GetStringDescriptor(hHubDevice, ConnectionIndex, 0, 0); if(String.IsNullOrEmpty(SupportedLanguagesString))return 0; UInt16 UserDefaultUILanguage = Splash.Environment.UserDefaultUILanguage; if(SupportedLanguagesString.IndexOf(Convert.ToChar(UserDefaultUILanguage)) != -1) { // 用户缺省界面语言 return UserDefaultUILanguage; } else if(SupportedLanguagesString.IndexOf(Convert.ToChar(0x0409)) != -1) { // 美国英语 0x0409 return 0x0409; } else { // 第一个可选择的LANGID return Convert.ToUInt16(SupportedLanguagesString[0]); } } #endregion #region EXTERNALHUB /// <summary> /// 获取外接Hub设备路径 /// </summary> /// <param name="ParentDevicePath">上层Hub设备路径</param> /// <param name="ConnectionIndex">连接索引号</param> /// <returns>外接Hub设备路径</returns> public static String GetExternalHubPath(String ParentDevicePath, Int32 ConnectionIndex) { if (String.IsNullOrEmpty(ParentDevicePath)) return null; // 打开设备文件 IntPtr hParentHubDevice = Kernel32.CreateFile( "\\\\.\\" + ParentDevicePath, NativeFileAccess.GENERIC_WRITE, NativeFileShare.FILE_SHARE_WRITE, IntPtr.Zero, NativeFileMode.OPEN_EXISTING, IntPtr.Zero, IntPtr.Zero); if (hParentHubDevice == Kernel32.INVALID_HANDLE_VALUE) return null; USB_NODE_CONNECTION_DRIVERKEY_NAME Buffer = new USB_NODE_CONNECTION_DRIVERKEY_NAME(); Buffer.ConnectionIndex = ConnectionIndex; Int32 nBytesReturned; Boolean Status = DeviceIoControl(hParentHubDevice, IOCTL_USB_GET_NODE_CONNECTION_NAME, ref Buffer, Marshal.SizeOf(Buffer), ref Buffer, Marshal.SizeOf(Buffer), out nBytesReturned, IntPtr.Zero); // 关闭设备文件 Kernel32.CloseHandle(hParentHubDevice); if (Status) return Buffer.DriverKeyName; else return null; } /// <summary> /// 获取外接Hub设备路径 /// </summary> /// <param name="hParentHubDevice">上层Hub设备句柄</param> /// <param name="ConnectionIndex">连接索引号</param> /// <returns>外接Hub设备路径</returns> public static String GetExternalHubPath(IntPtr hParentHubDevice, Int32 ConnectionIndex) { if (hParentHubDevice == IntPtr.Zero || ConnectionIndex <= 0) return null; USB_NODE_CONNECTION_DRIVERKEY_NAME Buffer = new USB_NODE_CONNECTION_DRIVERKEY_NAME(); Buffer.ConnectionIndex = ConnectionIndex; Int32 nBytesReturned; Boolean Status = DeviceIoControl(hParentHubDevice, IOCTL_USB_GET_NODE_CONNECTION_NAME, ref Buffer, Marshal.SizeOf(Buffer), ref Buffer, Marshal.SizeOf(Buffer), out nBytesReturned, IntPtr.Zero); if (Status) return Buffer.DriverKeyName; else return null; } #endregion #region BCDVERSION /// <summary> /// 版本BCD编码转字符串 /// </summary> /// <param name="bcd">版本BCD编码</param> /// <returns>版本字符串</returns> private static String BcdVersionToString(UInt16 bcd) { StringBuilder sb = new StringBuilder(5); // 主版本号 Int32 BIT4 = (bcd >> 12) & 0x0F; if (BIT4 != 0) sb.Append(BIT4.ToString()); BIT4 = (bcd >> 8) & 0x0F; sb.Append(BIT4.ToString()); sb.Append("."); // 子版本号 BIT4 = (bcd >> 4) & 0x0F; sb.Append(BIT4.ToString()); BIT4 = bcd & 0x0F; if (BIT4 != 0) sb.Append(BIT4.ToString()); return sb.ToString(); } #endregion } }
(三)输出枚举信息到XML文档
/* ---------------------------------------------------------- 文件名称:UsbEnumXML.cs 作者:秦建辉 MSN:splashcn@msn.com QQ:36748897 博客:http://blog.csdn.net/jhqin 开发环境: Visual Studio V2010 .NET Framework 4 Client Profile 版本历史: V1.0 2011年10月28日 将USB设备枚举信息导出为XML文档 ------------------------------------------------------------ */ using System; using System.Collections.Generic; using System.Xml.Linq; namespace Splash.IO.PORTS { /// <summary> /// 将USB设备信息写入XML文件 /// </summary> public partial class USB { /// <summary> /// 将USB设备枚举信息导出为XML文档 /// </summary> /// <param name="xmlFileName">保存的XML文件名</param> /// <returns> /// true:成功 /// false:失败 /// </returns> public static Boolean EnumUsbToXML(String xmlFileName) { // 创建根节点 XElement RootNode = new XElement("Computer", new XAttribute("MachineName", System.Environment.MachineName)); // 深度遍历主控制器 HostControllerInfo[] HostControllersCollection = USB.AllHostControllers; if (HostControllersCollection != null) { Int32 ControllerIndex = 1; foreach (HostControllerInfo item in HostControllersCollection) { // 创建主控制器节点 String PNPDeviceID = item.PNPDeviceID; String HcdDriverKeyName = USB.GetHcdDriverKeyName(PNPDeviceID); XElement HostControllerNode = new XElement("HostController" + ControllerIndex, new XAttribute("Name", item.Name), // 设备名称 new XAttribute("PNPDeviceID", PNPDeviceID), // 设备ID new XAttribute("HcdDriverKeyName", HcdDriverKeyName) // 驱动键名 ); RootNode.Add(HostControllerNode); ControllerIndex++; // 创建根集线器节点 String RootHubPath = USB.GetUsbRootHubPath(PNPDeviceID); AddHubNode(HostControllerNode, RootHubPath, "RootHub"); } } // 创建XML文档 XDocument xmlTree = new XDocument(RootNode); // 存储文件,序列化时对XML进行格式设置(缩进) xmlTree.Save(xmlFileName, SaveOptions.None); return true; } /// <summary> /// 增加集线器节点 /// </summary> /// <param name="ParentNode">父节点</param> /// <param name="HubPath">集线器路径</param> private static void AddHubNode(XElement ParentNode, String HubPath, String HubNodeName) { UsbNodeInformation[] NodeInfoCollection = USB.GetUsbNodeInformation(HubPath); if (NodeInfoCollection != null) { USB_HUB_NODE NodeType = NodeInfoCollection[0].NodeType; XElement HubNode = new XElement(HubNodeName, new XAttribute("Name", NodeInfoCollection[0].Name), new XAttribute("PNPDeviceID", NodeInfoCollection[0].PNPDeviceID), new XAttribute("Path", NodeInfoCollection[0].DevicePath), new XAttribute("NodeType", NodeType) ); if (NodeType == USB_HUB_NODE.UsbHub) { Int32 NumberOfPorts = NodeInfoCollection[0].NumberOfPorts; HubNode.Add(new XAttribute("NumberOfPorts", NumberOfPorts), new XAttribute("HubIsBusPowered", NodeInfoCollection[0].HubIsBusPowered), new XAttribute("HubCharacteristics", "0x" + NodeInfoCollection[0].HubCharacteristics.ToString("X4")), new XAttribute("PowerOnToPowerGood", NodeInfoCollection[0].PowerOnToPowerGood), new XAttribute("HubControlCurrent", NodeInfoCollection[0].HubControlCurrent) ); // 深度遍历端口 UsbNodeConnectionInformation[] NodeConnectionInfoCollection = USB.GetUsbNodeConnectionInformation(HubPath, NumberOfPorts); if (NodeConnectionInfoCollection != null) { foreach (UsbNodeConnectionInformation NodeConnectionInfo in NodeConnectionInfoCollection) { // 增加端口节点 AddPortNode(HubNode, NodeConnectionInfo); } } } else { HubNode.Add("NumberOfInterfaces", NodeInfoCollection[0].NumberOfInterfaces); } ParentNode.Add(HubNode); } } /// <summary> /// 增加端口节点 /// </summary> /// <param name="HubNode">集线器节点</param> /// <param name="NodeConnectionInfo">USB设备节点连接信息</param> private static void AddPortNode(XElement HubNode, UsbNodeConnectionInformation NodeConnectionInfo) { String DevicePath = NodeConnectionInfo.DevicePath; Int32 ConnectionIndex = NodeConnectionInfo.ConnectionIndex; USB_CONNECTION_STATUS ConnectionStatus = NodeConnectionInfo.ConnectionStatus; // 创建端口节点 XElement PortNode = new XElement("Port" + ConnectionIndex, new XAttribute("DevicePath", DevicePath), new XAttribute("ConnectionIndex", ConnectionIndex), new XAttribute("ConnectionStatus", NodeConnectionInfo.ConnectionStatus) ); if (ConnectionStatus == USB_CONNECTION_STATUS.DeviceConnected) { Boolean DeviceIsHub = NodeConnectionInfo.DeviceIsHub; PortNode.Add(new XAttribute("DeviceIsHub", DeviceIsHub), new XAttribute("CurrentConfigurationValue", NodeConnectionInfo.CurrentConfigurationValue), new XAttribute("Speed", NodeConnectionInfo.Speed), new XAttribute("DeviceAddress", NodeConnectionInfo.DeviceAddress), new XAttribute("NumberOfOpenPipes", NodeConnectionInfo.NumberOfOpenPipes) ); // 设备描述符信息 AddDeviceDescriptorNode(PortNode, ref NodeConnectionInfo.DeviceDescriptor); // 管道信息 AddPipeInfoNode(PortNode, ref NodeConnectionInfo.PipeList); // 外部集线器 if (DeviceIsHub) { // 获取外部Hub设备路径 String ExternalHubPath = GetExternalHubPath(DevicePath, ConnectionIndex); // 增加外部集线器节点 AddHubNode(PortNode, ExternalHubPath, "ExternalHub"); } } HubNode.Add(PortNode); } /// <summary> /// 增加设备描述符节点 /// </summary> /// <param name="PortNode"></param> /// <param name="DeviceDescriptor"></param> private static void AddDeviceDescriptorNode(XElement PortNode, ref UsbDeviceDescriptor DeviceDescriptor) { XElement DeviceDescriptorNode = new XElement("DeviceDescriptor", new XAttribute("bDescriptorType", "0x" + DeviceDescriptor.bDescriptorType.ToString("X2")), new XAttribute("UsbVersion", DeviceDescriptor.UsbVersion), new XAttribute("bDeviceClass", "0x" + DeviceDescriptor.bDeviceClass.ToString("X2")), new XAttribute("bDeviceSubClass", "0x" + DeviceDescriptor.bDeviceSubClass.ToString("X2")), new XAttribute("bDeviceProtocol", "0x" + DeviceDescriptor.bDeviceProtocol.ToString("X2")), new XAttribute("bMaxPacketSize0", DeviceDescriptor.bMaxPacketSize0), new XAttribute("bNumConfigurations", DeviceDescriptor.bNumConfigurations) ); if (DeviceDescriptor.idVendor != 0) { DeviceDescriptorNode.Add(new XAttribute("idVendor", "0x" + DeviceDescriptor.idVendor.ToString("X4"))); } if (DeviceDescriptor.idProduct != 0) { DeviceDescriptorNode.Add(new XAttribute("idProduct", "0x" + DeviceDescriptor.idProduct.ToString("X4"))); } if (!String.IsNullOrEmpty(DeviceDescriptor.DeviceVersion)) { DeviceDescriptorNode.Add(new XAttribute("DeviceVersion", DeviceDescriptor.DeviceVersion)); } if (!String.IsNullOrEmpty(DeviceDescriptor.Manufacturer)) { DeviceDescriptorNode.Add(new XAttribute("Manufacturer", DeviceDescriptor.Manufacturer)); } if (!String.IsNullOrEmpty(DeviceDescriptor.Product)) { DeviceDescriptorNode.Add(new XAttribute("Product", DeviceDescriptor.Product)); } if (!String.IsNullOrEmpty(DeviceDescriptor.SerialNumber)) { DeviceDescriptorNode.Add(new XAttribute("SerialNumber", DeviceDescriptor.SerialNumber)); } PortNode.Add(DeviceDescriptorNode); } /// <summary> /// 增加管道信息节点 /// </summary> /// <param name="PortNode">端口节点</param> /// <param name="PipeList">管道信息列表</param> private static void AddPipeInfoNode(XElement PortNode, ref List<UsbPipeInfo> PipeList) { if(PipeList != null) { XElement PipeListNode = new XElement("PipeList"); Int32 PipeIndex = 1; foreach(UsbPipeInfo item in PipeList) { XElement PipeInfoNode = new XElement("Pipe" + PipeIndex, new XAttribute("ScheduleOffset", item.ScheduleOffset), new XAttribute("bDescriptorType", "0x" + item.bDescriptorType.ToString("X2")), new XAttribute("bEndpointAddress", "0x" + item.bEndpointAddress.ToString("X2")), new XAttribute("bmAttributes", "0x" + item.bmAttributes.ToString("X2")), new XAttribute("wMaxPacketSize", item.wMaxPacketSize), new XAttribute("bInterval", item.bInterval) ); PipeListNode.Add(PipeInfoNode); PipeIndex++; } PortNode.Add(PipeListNode); } } } }
(四)Kernel32的PInvoke
/* ---------------------------------------------------------- 文件名称:Kernel32.cs 作者:秦建辉 MSN:splashcn@msn.com QQ:36748897 博客:http://blog.csdn.net/jhqin 开发环境: Visual Studio V2010 .NET Framework 4 Client Profile 版本历史: V1.0 2011年09月05日 实现对Kernel32.dll接口的PInvoke 参考资料: http://www.pinvoke.net/ ------------------------------------------------------------ */ using System; using System.Runtime.InteropServices; using System.Security; namespace Splash { #region Kernel32 [SuppressUnmanagedCodeSecurity] internal static class Kernel32 { /// <summary> /// 无效的文件句柄 /// </summary> public static readonly IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1); #region CreateFile [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] public static extern IntPtr CreateFile( String fileName, [MarshalAs(UnmanagedType.U4)] NativeFileAccess fileAccess, [MarshalAs(UnmanagedType.U4)] NativeFileShare fileShare, IntPtr securityAttributes, [MarshalAs(UnmanagedType.U4)] NativeFileMode creationDisposition, NativeFileFlag flags, IntPtr template ); [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] public static extern IntPtr CreateFile( String fileName, [MarshalAs(UnmanagedType.U4)] NativeFileAccess fileAccess, [MarshalAs(UnmanagedType.U4)] NativeFileShare fileShare, IntPtr securityAttributes, [MarshalAs(UnmanagedType.U4)] NativeFileMode creationDisposition, IntPtr flags, IntPtr template ); #endregion [DllImport("kernel32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern Boolean CloseHandle(IntPtr hFile); #region ReadFile [DllImport("kernel32.dll", SetLastError = true)] public static extern Boolean ReadFile( IntPtr hFile, [Out] Byte[] lpBuffer, Int32 nNumberOfBytesToRead, out Int32 lpNumberOfBytesRead, [In] ref System.Threading.NativeOverlapped lpOverlapped ); [DllImport("kernel32.dll", SetLastError = true)] public static extern Boolean ReadFile( IntPtr hFile, [Out] Byte[] lpBuffer, Int32 nNumberOfBytesToRead, IntPtr lpNumberOfBytesRead, [In] ref System.Threading.NativeOverlapped lpOverlapped ); [DllImport("kernel32.dll", SetLastError = true)] public static extern Boolean ReadFile( IntPtr hFile, [Out] Byte[] lpBuffer, Int32 nNumberOfBytesToRead, out Int32 lpNumberOfBytesRead, IntPtr lpOverlapped ); #endregion #region WriteFile [DllImport("kernel32.dll")] public static extern Boolean WriteFile( IntPtr hFile, Byte[] lpBuffer, Int32 nNumberOfBytesToWrite, out Int32 lpNumberOfBytesWritten, [In] ref System.Threading.NativeOverlapped lpOverlapped ); [DllImport("kernel32.dll")] public static extern Boolean WriteFile( IntPtr hFile, Byte[] lpBuffer, Int32 nNumberOfBytesToWrite, IntPtr lpNumberOfBytesWritten, [In] ref System.Threading.NativeOverlapped lpOverlapped ); [DllImport("kernel32.dll")] public static extern Boolean WriteFile( IntPtr hFile, Byte[] lpBuffer, Int32 nNumberOfBytesToWrite, IntPtr lpNumberOfBytesWritten, IntPtr lpOverlapped ); #endregion [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] public static extern Boolean GetOverlappedResult( IntPtr hFile, [In] ref System.Threading.NativeOverlapped lpOverlapped, out Int32 lpNumberOfBytesTransferred, Boolean bWait ); } #endregion #region ENUM [Flags] internal enum NativeFileAccess : uint { GENERIC_READ = (0x80000000), GENERIC_WRITE = (0x40000000), GENERIC_EXECUTE = (0x20000000), GENERIC_ALL = (0x10000000), FILE_SPECIAL = 0, FILE_APPEND_DATA = (0x0004), // 文件 FILE_READ_DATA = (0x0001), // 文件和管道 FILE_WRITE_DATA = (0x0002), // 文件和管道 FILE_READ_EA = (0x0008), // 文件和目录 FILE_WRITE_EA = (0x0010), // 文件和目录 FILE_READ_ATTRIBUTES = (0x0080), // 所有 FILE_WRITE_ATTRIBUTES = (0x0100), // 所有 DELETE = 0x00010000, READ_CONTROL = (0x00020000), WRITE_DAC = (0x00040000), WRITE_OWNER = (0x00080000), SYNCHRONIZE = (0x00100000), STANDARD_RIGHTS_REQUIRED = (0x000F0000), STANDARD_RIGHTS_READ = (READ_CONTROL), STANDARD_RIGHTS_WRITE = (READ_CONTROL), STANDARD_RIGHTS_EXECUTE = (READ_CONTROL), STANDARD_RIGHTS_ALL = (0x001F0000), SPECIFIC_RIGHTS_ALL = (0x0000FFFF), FILE_GENERIC_READ = (STANDARD_RIGHTS_READ | FILE_READ_DATA | FILE_READ_ATTRIBUTES | FILE_READ_EA | SYNCHRONIZE), FILE_GENERIC_WRITE = (STANDARD_RIGHTS_WRITE | FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | FILE_APPEND_DATA | SYNCHRONIZE), SPECIAL = 0 } internal enum NativeFileMode : uint { CREATE_NEW = 1, CREATE_ALWAYS = 2, OPEN_EXISTING = 3, OPEN_ALWAYS = 4, TRUNCATE_EXISTING = 5, } [Flags] internal enum NativeFileShare : uint { NONE = 0, FILE_SHARE_READ = 0x00000001, FILE_SHARE_WRITE = 0x00000002, FILE_SHARE_DEELETE = 0x00000004, } [Flags] internal enum NativeFileFlag : uint { FILE_ATTRIBUTE_READONLY = 0x00000001, FILE_ATTRIBUTE_HIDDEN = 0x00000002, FILE_ATTRIBUTE_SYSTEM = 0x00000004, FILE_ATTRIBUTE_DIRECTORY = 0x00000010, FILE_ATTRIBUTE_ARCHIVE = 0x00000020, FILE_ATTRIBUTE_DEVICE = 0x00000040, FILE_ATTRIBUTE_NORMAL = 0x00000080, FILE_ATTRIBUTE_TEMPORARY = 0x00000100, FILE_ATTRIBUTE_SPARSE_FILE = 0x00000200, FILE_ATTRIBUTE_REPARSE_POINT = 0x00000400, FILE_ATTRIBUTE_COMPRESSED = 0x00000800, FILE_ATTRIBUTE_OFFLINE = 0x00001000, FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x00002000, FILE_ATTRIBUTE_ENCRYPTED = 0x00004000, FILE_FLAG_WRITE_THROUGH = 0x80000000, FILE_FLAG_OVERLAPPED = 0x40000000, FILE_FLAG_NO_BUFFERING = 0x20000000, FILE_FLAG_RANDOM_ACCESS = 0x10000000, FILE_FLAG_SEQUENTIAL_SCAN = 0x08000000, FILE_FLAG_DELETE_ON_CLOSE = 0x04000000, FILE_FLAG_BACKUP_SEMANTICS = 0x02000000, FILE_FLAG_POSIX_SEMANTICS = 0x01000000, FILE_FLAG_OPEN_REPARSE_POINT = 0x00200000, FILE_FLAG_OPEN_NO_RECALL = 0x00100000, FILE_FLAG_FIRST_PIPE_INSTANCE = 0x00080000, } #endregion }
USB设备枚举(五)生成TreeView数据源
有一处错误已于2014年5月8日修正。请大家下载SkyDrive上的资源。
/* ---------------------------------------------------------- * 文件名称:TreeViewUsbItem.cs * * 作者:秦建辉 * * QQ:36748897 * * 博客:http://www.firstsolver.com/wordpress/ * * 开发环境: * Visual Studio V2010 * .NET Framework 4 Client Profile * * 版本历史: * V1.0 2014年05月08日 * 修正由网友指出的一处错误 * * V1.0 2011年10月26日 * 为USB设备枚举信息生成TreeView数据源 ------------------------------------------------------------ */ using System; using System.Collections.Generic; using System.Windows.Media; using System.Windows.Media.Imaging; using Splash.IO.PORTS; namespace WPFUsbView { /// <summary> /// TreeView节点对象 /// </summary> internal class TreeViewUsbItem { /// <summary> /// 节点图标 /// </summary> public ImageSource Icon { get; set; } /// <summary> /// 节点名称 /// </summary> public String Name { get; set; } /// <summary> /// 节点数据 /// </summary> public Object Data { get; set; } /// <summary> /// 子节点列表 /// </summary> public List<TreeViewUsbItem> Children { get; set; } /// <summary> /// 计算机图标 /// </summary> public static ImageSource ImageComputer { get { return System.Windows.Interop.Imaging.CreateBitmapSourceFromHIcon( Properties.Resources.notebook.Handle, System.Windows.Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions() ); } } /// <summary> /// 主控制器图标 /// </summary> public static ImageSource ImageHostController { get { return System.Windows.Interop.Imaging.CreateBitmapSourceFromHIcon( Properties.Resources.usb.Handle, System.Windows.Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions() ); } } /// <summary> /// Hub图标 /// </summary> public static ImageSource ImageHub { get { return System.Windows.Interop.Imaging.CreateBitmapSourceFromHIcon( Properties.Resources.hub.Handle, System.Windows.Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions() ); } } /// <summary> /// USB设备图标 /// </summary> public static ImageSource ImageDevice { get { return System.Windows.Interop.Imaging.CreateBitmapSourceFromHIcon( Properties.Resources.port.Handle, System.Windows.Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions() ); } } /// <summary> /// 连接的外部Hub数目 /// </summary> public static Int32 ConnectedHubs = 0; /// <summary> /// 连接的USB设备数目 /// </summary> public static Int32 ConnectedDevices = 0; /// <summary> /// 静态根节点 /// </summary> public static List<TreeViewUsbItem> AllUsbDevices { get { // 初始化 ConnectedHubs = 0; // 连接的外部Hub数目 ConnectedDevices = 0; // 连接的USB设备数目 // 创建根节点 TreeViewUsbItem Root = new TreeViewUsbItem(); Root.Icon = ImageComputer; Root.Name = "Computer"; Root.Data = "Machine Name:" + System.Environment.MachineName; // 子节点列表 // 深度遍历主控制器 HostControllerInfo[] HostControllersCollection = USB.AllHostControllers; if (HostControllersCollection != null) { List<TreeViewUsbItem> HCNodeCollection = new List<TreeViewUsbItem>(HostControllersCollection.Length); foreach (HostControllerInfo item in HostControllersCollection) { // 创建主控制器节点 TreeViewUsbItem HCNode = new TreeViewUsbItem(); HCNode.Icon = ImageHostController; HCNode.Name = item.Name; HCNode.Data = item; // 创建根集线器节点 String RootHubPath = USB.GetUsbRootHubPath(item.PNPDeviceID); HCNode.Children = AddHubNode(RootHubPath, "RootHub"); HCNodeCollection.Add(HCNode); } Root.Children = HCNodeCollection; } return new List<TreeViewUsbItem>(1) { Root }; } } /// <summary> /// Hub节点 /// </summary> /// <param name="HubPath">Hub路径</param> /// <param name="HubNodeName">节点显示名称</param> /// <returns>Hub节点集合</returns> private static List<TreeViewUsbItem> AddHubNode(String HubPath, String HubNodeName) { UsbNodeInformation[] NodeInfoCollection = USB.GetUsbNodeInformation(HubPath); if (NodeInfoCollection != null) { TreeViewUsbItem HubNode = new TreeViewUsbItem(); HubNode.Icon = ImageHub; if (String.IsNullOrEmpty(NodeInfoCollection[0].Name)) { HubNode.Name = HubNodeName; } else { HubNode.Name = NodeInfoCollection[0].Name; } HubNode.Data = NodeInfoCollection[0]; if (NodeInfoCollection[0].NodeType == USB_HUB_NODE.UsbHub) { HubNode.Children = AddPortNode(HubPath, NodeInfoCollection[0].NumberOfPorts); } else { HubNode.Children = null; } return new List<TreeViewUsbItem>(1) { HubNode }; } return null; } /// <summary> /// Port节点 /// </summary> /// <param name="HubPath">Hub路径</param> /// <param name="NumberOfPorts">端口数</param> /// <returns>Port节点集合</returns> private static List<TreeViewUsbItem> AddPortNode(String HubPath, Int32 NumberOfPorts) { // 深度遍历端口 UsbNodeConnectionInformation[] NodeConnectionInfoCollection = USB.GetUsbNodeConnectionInformation(HubPath, NumberOfPorts); if (NodeConnectionInfoCollection != null) { List<TreeViewUsbItem> PortNodeCollection = new List<TreeViewUsbItem>(NumberOfPorts); foreach (UsbNodeConnectionInformation NodeConnectionInfo in NodeConnectionInfoCollection) { // 增加端口节点 TreeViewUsbItem PortNode = new TreeViewUsbItem(); PortNode.Icon = ImageDevice; PortNode.Name = "[Port" + NodeConnectionInfo.ConnectionIndex + "]" + NodeConnectionInfo.ConnectionStatus; PortNode.Data = NodeConnectionInfo; PortNode.Children = null; if (NodeConnectionInfo.ConnectionStatus == USB_CONNECTION_STATUS.DeviceConnected) { // 设备连接 ConnectedDevices++; // 连接的USB设备数目 if (!String.IsNullOrEmpty(NodeConnectionInfo.DeviceDescriptor.Product)) { // 产品名称 PortNode.Name = String.Concat(PortNode.Name, ": ", NodeConnectionInfo.DeviceDescriptor.Product); } if (NodeConnectionInfo.DeviceIsHub) { // 获取外部Hub设备路径 String ExternalHubPath = USB.GetExternalHubPath(NodeConnectionInfo.DevicePath, NodeConnectionInfo.ConnectionIndex); UsbNodeInformation[] NodeInfoCollection = USB.GetUsbNodeInformation(ExternalHubPath); if (NodeInfoCollection != null) { PortNode.Icon = ImageHub; PortNode.Data = new ExternalHubInfo { NodeInfo = NodeInfoCollection[0], NodeConnectionInfo = NodeConnectionInfo }; if (NodeInfoCollection[0].NodeType == USB_HUB_NODE.UsbHub) { PortNode.Children = AddPortNode(ExternalHubPath, NodeInfoCollection[0].NumberOfPorts); } if (String.IsNullOrEmpty(NodeConnectionInfo.DeviceDescriptor.Product)) { if (!String.IsNullOrEmpty(NodeInfoCollection[0].Name)) { // 产品名称 PortNode.Name = String.Concat(PortNode.Name, ": ", NodeInfoCollection[0].Name); } } } ConnectedHubs++; // 连接的外部Hub数目 } } PortNodeCollection.Add(PortNode); } return PortNodeCollection; } return null; } } }
USB设备枚举(六)生成ListView数据源
/* ---------------------------------------------------------- 文件名称:ListViewUsbItem.cs 作者:秦建辉 MSN:splashcn@msn.com QQ:36748897 博客:http://blog.csdn.net/jhqin 开发环境: Visual Studio V2010 .NET Framework 4 Client Profile 版本历史: V1.0 2011年11月08日 为USB设备枚举信息生成ListView数据源 ------------------------------------------------------------ */ using System; using System.Collections.Generic; using Splash.IO.PORTS; namespace WPFUsbView { /// <summary> /// TreeView节点对象 /// </summary> internal class ListViewUsbItem { /// <summary> /// USB属性名 /// </summary> public String Name { get; set; } /// <summary> /// USB属性值 /// </summary> public String Value { get; set; } /// <summary> /// 构造函数 /// </summary> /// <param name="Name">USB属性名</param> /// <param name="Value">USB属性值</param> public ListViewUsbItem(String Name, String Value) { this.Name = Name; this.Value = Value; } /// <summary> /// 生成USB属性列表 /// </summary> /// <param name="Data">用于生成列表的USB数据</param> /// <returns>属性列表</returns> public static List<ListViewUsbItem> UsbDetail(Object Data) { if (Data is String) { // 机器名 String Info = Data as String; if (!String.IsNullOrEmpty(Info)) { String[] Content = Info.Split(new Char[] { ‘:‘ }); if (Content.Length == 2) { return new List<ListViewUsbItem>(1) { new ListViewUsbItem(Content[0], Content[1]) }; } } } else if (Data is HostControllerInfo) { // 主控制器信息 HostControllerInfo Info = (HostControllerInfo)Data; return new List<ListViewUsbItem>(3) { new ListViewUsbItem("Name", Info.Name), new ListViewUsbItem("PNPDeviceID", Info.PNPDeviceID), new ListViewUsbItem("HcdDriverKeyName", Info.HcdDriverKeyName) }; } else if (Data is UsbNodeInformation) { // USB节点信息 UsbNodeInformation Info = (UsbNodeInformation)Data; List<ListViewUsbItem> Items = new List<ListViewUsbItem>(); Add(ref Items, Info); return Items; } else if (Data is UsbNodeConnectionInformation) { // USB节点连接信息 UsbNodeConnectionInformation Info = (UsbNodeConnectionInformation)Data; if(Info.ConnectionStatus != USB_CONNECTION_STATUS.DeviceConnected) return null; List<ListViewUsbItem> Items = new List<ListViewUsbItem>(); Add(ref Items, Info); return Items; } else if (Data is ExternalHubInfo) { // 外部Hub信息 ExternalHubInfo Info = (ExternalHubInfo)Data; List<ListViewUsbItem> Items = new List<ListViewUsbItem>(); // 加入USB节点信息 Items.Add(new ListViewUsbItem("Node Information:", null)); Add(ref Items, Info.NodeInfo); // 加入USB节点连接信息 Items.Add(new ListViewUsbItem(null, null)); Items.Add(new ListViewUsbItem("Node Connection Information:", null)); Add(ref Items, Info.NodeConnectionInfo); return Items; } return null; } /// <summary> /// 增加USB节点信息 /// </summary> /// <param name="Items">要增加的列表</param> /// <param name="Info">要增加的信息</param> private static void Add(ref List<ListViewUsbItem> Items, UsbNodeInformation Info) { if (Info.NodeType == USB_HUB_NODE.UsbHub) { Items.Add(new ListViewUsbItem("Name", Info.Name)); Items.Add(new ListViewUsbItem("PNPDeviceID", Info.PNPDeviceID)); Items.Add(new ListViewUsbItem("DevicePath", Info.DevicePath)); Items.Add(new ListViewUsbItem("NodeType", Info.NodeType.ToString())); Items.Add(new ListViewUsbItem("HubIsBusPowered", Info.HubIsBusPowered.ToString())); Items.Add(new ListViewUsbItem("NumberOfPorts", Info.NumberOfPorts.ToString())); Items.Add(new ListViewUsbItem("HubCharacteristics", "0x" + Info.HubCharacteristics.ToString("X4"))); Items.Add(new ListViewUsbItem("PowerOnToPowerGood", (Info.PowerOnToPowerGood * 2).ToString() + "ms")); Items.Add(new ListViewUsbItem("HubControlCurrent", Info.HubControlCurrent.ToString())); } else { Items.Add(new ListViewUsbItem("Name", Info.Name)); Items.Add(new ListViewUsbItem("PNPDeviceID", Info.PNPDeviceID)); Items.Add(new ListViewUsbItem("DevicePath", Info.DevicePath)); Items.Add(new ListViewUsbItem("NodeType", Info.NodeType.ToString())); Items.Add(new ListViewUsbItem("NumberOfInterfaces", Info.NumberOfInterfaces.ToString())); } } /// <summary> /// 增加USB节点连接信息 /// </summary> /// <param name="Items">要增加的列表</param> /// <param name="Info">要增加的信息</param> private static void Add(ref List<ListViewUsbItem> Items, UsbNodeConnectionInformation Info) { Items.Add(new ListViewUsbItem("DevicePath", Info.DevicePath)); Items.Add(new ListViewUsbItem("ConnectionIndex", Info.ConnectionIndex.ToString())); Items.Add(new ListViewUsbItem("CurrentConfigurationValue", "0x" + Info.CurrentConfigurationValue.ToString("X2"))); Items.Add(new ListViewUsbItem("Speed", ((USB_DEVICE_SPEED)Info.Speed).ToString())); Items.Add(new ListViewUsbItem("DeviceIsHub", Info.DeviceIsHub.ToString())); Items.Add(new ListViewUsbItem("DeviceAddress", Info.DeviceAddress.ToString())); Items.Add(new ListViewUsbItem("NumberOfOpenPipes", Info.NumberOfOpenPipes.ToString())); // 设备描述符 Items.Add(new ListViewUsbItem(null, null)); Items.Add(new ListViewUsbItem("Device Descriptor:", null)); Items.Add(new ListViewUsbItem("DescriptorType", "0x" + Info.DeviceDescriptor.bDescriptorType.ToString("X2"))); Items.Add(new ListViewUsbItem("UsbVersion", Info.DeviceDescriptor.UsbVersion)); Items.Add(new ListViewUsbItem("DeviceClass", "0x" + Info.DeviceDescriptor.bDeviceClass.ToString("X2"))); Items.Add(new ListViewUsbItem("DeviceSubClass", "0x" + Info.DeviceDescriptor.bDeviceSubClass.ToString("X2"))); Items.Add(new ListViewUsbItem("DeviceProtocol", "0x" + Info.DeviceDescriptor.bDeviceProtocol.ToString("X2"))); Items.Add(new ListViewUsbItem("MaxPacketSize0", Info.DeviceDescriptor.bMaxPacketSize0.ToString())); Items.Add(new ListViewUsbItem("idVendor", "0x" + Info.DeviceDescriptor.idVendor.ToString("X4"))); Items.Add(new ListViewUsbItem("idProduct", "0x" + Info.DeviceDescriptor.idProduct.ToString("X4"))); Items.Add(new ListViewUsbItem("DeviceVersion", Info.DeviceDescriptor.DeviceVersion)); Items.Add(new ListViewUsbItem("Manufacturer", Info.DeviceDescriptor.Manufacturer)); Items.Add(new ListViewUsbItem("Product", Info.DeviceDescriptor.Product)); Items.Add(new ListViewUsbItem("SerialNumber", Info.DeviceDescriptor.SerialNumber)); Items.Add(new ListViewUsbItem("NumConfigurations", Info.DeviceDescriptor.bNumConfigurations.ToString())); // 管道信息 foreach (UsbPipeInfo Pipe in Info.PipeList) { Items.Add(new ListViewUsbItem(null, null)); Items.Add(new ListViewUsbItem("Endpoint Descriptor:", null)); Items.Add(new ListViewUsbItem("ScheduleOffset", Pipe.ScheduleOffset.ToString())); Items.Add(new ListViewUsbItem("DescriptorType", "0x" + Pipe.bDescriptorType.ToString("X2"))); Items.Add(new ListViewUsbItem("EndpointAddress", "0x" + Pipe.bEndpointAddress.ToString("X2"))); Items.Add(new ListViewUsbItem("bmAttributes", "0x" + Pipe.bmAttributes.ToString("X2"))); Items.Add(new ListViewUsbItem("MaxPacketSize", Pipe.wMaxPacketSize.ToString())); Items.Add(new ListViewUsbItem("Interval", "0x" + Pipe.bInterval.ToString("X2"))); } } } }
USB设备枚举(七)WPF扩展方法
/* ---------------------------------------------------------- 文件名称:WPFExtensions.cs 作者:秦建辉 MSN:splashcn@msn.com QQ:36748897 博客:http://blog.csdn.net/jhqin 开发环境: Visual Studio V2010 .NET Framework 4 Client Profile 版本历史: V1.1 2011年11月07日 实现扩展方法:WPF中TreeView类的ExpandAll功能 V1.0 2011年11月03日 实现扩展方法:WPF中Button类的PerformClick功能 ------------------------------------------------------------ */ using System.Windows.Controls; using System.Windows.Automation.Peers; using System.Windows.Automation.Provider; namespace Splash.WPF { /// <summary> /// 扩展方法 /// </summary> public static partial class Extensions { /// <summary> /// 扩展方法:实现WPF中Button类的PerformClick功能 /// </summary> /// <param name="button">Button实例</param> /// <remarks> /// 需要添加对UIAutomationProvider.dll的引用 /// 参考网址:http://www.cnblogs.com/zhouyinhui/archive/2010/05/20/1740111.html /// </remarks> public static void PerformClick(this Button button) { ButtonAutomationPeer BAP = new ButtonAutomationPeer(button); IInvokeProvider IIP = BAP.GetPattern(PatternInterface.Invoke) as IInvokeProvider; if (IIP != null) { IIP.Invoke(); } } /// <summary> /// 扩展方法:实现WPF中TreeView类的ExpandAll功能 /// </summary> /// <param name="treeView">要展开的TreeView实例</param> /// <remarks> /// 参考网址:http://www.cnblogs.com/sayo/archive/2008/07/23/1249804.html /// </remarks> public static void ExpandAll(this TreeView treeView) { ExpandSubItems(treeView as ItemsControl); } private static void ExpandSubItems(ItemsControl control) { if (control == null) return; foreach (object item in control.Items) { TreeViewItem treeItem = control.ItemContainerGenerator.ContainerFromItem(item) as TreeViewItem; if (treeItem != null && treeItem.HasItems) { treeItem.IsExpanded = true; ExpandSubItems(treeItem as ItemsControl); } } } } }
(八)创建基于WPF的USB设备浏览器
软件界面:
下载地址(包含产品及源代码):
微软SkyDrive下载链接:WPFUsbView.zip
源代码:
MainWindow.xaml
<Window x:Class="WPFUsbView.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:usb="clr-namespace:WPFUsbView" Title="USB Device Viewer" Height="600" Width="800" Icon="/WPFUsbView;component/images/usb.ico" WindowStyle="ThreeDBorderWindow" WindowStartupLocation="CenterScreen" Loaded="Window_Loaded" WindowState="Maximized"> <Window.Resources> <Style TargetType="TreeViewItem"> <Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=OneWay, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TreeViewItem}}}" /> </Style> </Window.Resources> <Grid> <Grid.RowDefinitions> <RowDefinition Height="Auto"></RowDefinition> <RowDefinition Height="*"></RowDefinition> <RowDefinition Height="Auto"></RowDefinition> </Grid.RowDefinitions> <Grid Grid.Row="0" Background="CadetBlue"> <ToolBar Height="40" Width="Auto" HorizontalAlignment="Left" Background="CadetBlue"> <Button Margin="4,0" Name="buttonRefresh" Click="buttonRefresh_Click"> <Image Source="/WPFUsbView;component/images/refresh.png"></Image> </Button> <Button Margin="4,0" Name="buttonOpenXML" Click="buttonOpenXML_Click"> <Image Source="/WPFUsbView;component/images/XML.png"></Image> </Button> <Button Margin="4,0" Name="buttonInfo" Click="buttonInfo_Click"> <Image Source="/WPFUsbView;component/images/Info.png"></Image> </Button> </ToolBar> </Grid> <Grid Grid.Row="1" Name="gridDetail"> <Grid.ColumnDefinitions> <ColumnDefinition Width="4*"></ColumnDefinition> <ColumnDefinition Width="Auto"></ColumnDefinition> <ColumnDefinition Width="6*"></ColumnDefinition> </Grid.ColumnDefinitions> <TreeView Grid.Column="0" HorizontalAlignment="Left" VerticalAlignment="Top" Name="treeView1" FontSize="16" SelectedItemChanged="treeView1_SelectedItemChanged"> <TreeView.ItemTemplate> <HierarchicalDataTemplate DataType="{x:Type usb:TreeViewUsbItem}" ItemsSource="{Binding Path=Children}"> <StackPanel Orientation="Horizontal"> <Image VerticalAlignment="Center" Source="{Binding Icon}" Width="16" Height="16" Margin="0,0,2,2"></Image> <TextBlock VerticalAlignment="Center" Text="{Binding Name}"></TextBlock> </StackPanel> </HierarchicalDataTemplate> </TreeView.ItemTemplate> </TreeView> <GridSplitter Grid.Column="1" Width="13" HorizontalAlignment="Center" VerticalAlignment="Stretch" LayoutUpdated="GridSplitter_LayoutUpdated"> <GridSplitter.Background> <ImageBrush ImageSource="/WPFUsbView;component/images/SplitLine.png" Stretch="UniformToFill" TileMode="Tile" Viewport="0,0,15,500" ViewportUnits="Absolute" /> </GridSplitter.Background> </GridSplitter> <ListView Grid.Column="2" Name="listView1" FontSize="16"> <ListView.ItemTemplate> <DataTemplate DataType="{x:Type usb:ListViewUsbItem}"> <StackPanel Orientation="Horizontal" Margin="0,2"> <TextBlock Width="250" Text="{Binding Name}"></TextBlock> <TextBlock Width="Auto" Text="{Binding Value}" Foreground="Blue"></TextBlock> </StackPanel> </DataTemplate> </ListView.ItemTemplate> </ListView> </Grid> <StatusBar Grid.Row="2" Height="32" Background="SteelBlue"> <StatusBarItem> <Image Source="/WPFUsbView;component/images/usbdevice.png"></Image> </StatusBarItem> <StatusBarItem> <TextBlock FontSize="16" Foreground="Brown" Name="textBlockUsbDevice">0</TextBlock> </StatusBarItem> <StatusBarItem> <Image Source="/WPFUsbView;component/images/usb-hub.png"></Image> </StatusBarItem> <StatusBarItem> <TextBlock FontSize="16" Foreground="Brown" Name="textBlockUsbHub">0</TextBlock> </StatusBarItem> </StatusBar> </Grid> </Window>
MainWindow.xaml.cs
using System; using System.IO; using System.Windows; using Splash.IO.PORTS; using Splash.WPF; namespace WPFUsbView { /// <summary> /// MainWindow.xaml 的交互逻辑 /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } // 枚举设备信息并输出到XML文档 private void buttonOpenXML_Click(object sender, RoutedEventArgs e) { String xmlFile = "UsbEnums.xml"; try { // 检测当前目录下是否可以创建文件 using (StreamWriter sw = new StreamWriter(xmlFile)) { sw.Close(); } } catch(Exception) { // 当前目录无法创建文件,改到我的文档目录下 xmlFile = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "\\" + xmlFile; } if (USB.EnumUsbToXML(xmlFile)) { // 判断文件是否存在 if (System.IO.File.Exists(xmlFile)) { // 打开文件 Splash.Diagnostics.Extensions.ShellExecute(xmlFile); return; } } MessageBox.Show("Failed!"); return; } // 更新设备枚举信息 private void buttonRefresh_Click(object sender, RoutedEventArgs e) { // 枚举USB设备信息 treeView1.ItemsSource = TreeViewUsbItem.AllUsbDevices; // 展开所有分支 treeView1.ExpandAll(); // 设备连接数 textBlockUsbDevice.Text = TreeViewUsbItem.ConnectedDevices.ToString(); // 外部Hub连接数 textBlockUsbHub.Text = TreeViewUsbItem.ConnectedHubs.ToString(); } // 显示软件版本信息 private void buttonInfo_Click(object sender, RoutedEventArgs e) { About AboutWindow = new About(); AboutWindow.Owner = this; AboutWindow.ShowDialog(); } private void Window_Loaded(object sender, RoutedEventArgs e) { // 显示USB设备枚举信息 buttonRefresh.PerformClick(); } // 更新布局,调整各控件大小 private void GridSplitter_LayoutUpdated(object sender, EventArgs e) { // 设置TreeView的宽度和高度 treeView1.Width = gridDetail.ColumnDefinitions[0].ActualWidth; treeView1.Height = gridDetail.ActualHeight; } private void treeView1_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e) { TreeViewUsbItem Node = e.NewValue as TreeViewUsbItem; if (Node != null) { listView1.ItemsSource = ListViewUsbItem.UsbDetail(Node.Data); } } } }