/* ----------------------------------------------------------
文件名稱:WDKUsbEnum.cs
作者:秦建輝
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
}
}