从VID / PID查找USB驱动器盘符(需要XP及更高版本)

所以我想我会在这里包括最终答案,所以你不必理解这篇文章。 非常感谢Simon Mourier抽出时间来解决这个问题。

我的工作代码

try { //Get a list of available devices attached to the USB hub List disks = new List(); var usbDevices = GetUSBDevices(); //Enumerate the USB devices to see if any have specific VID/PID foreach (var usbDevice in usbDevices) { if (usbDevice.DeviceID.Contains(USB_PID) && usbDevice.DeviceID.Contains(USB_VID)) { foreach (string name in usbDevice.GetDiskNames()) { //Open dialog to show file names textbox1.Text = name.ToString(); } } } 

所以只需从原始问题中使用GetUSBDevices ,然后包含Simon Mourier的答案所显示的两个类,它应该是好的去!


原始问题

我知道之前已经问过这个问题(见这里 )但是他们都没有得到确认答案,我已经尝试了所有建议的答案。 不幸的是,这些线程已经很久了,我希望有人可以在这里给出更好的答案。

到目前为止,我有两个“起点”,每个都将在下面显示。


选项1 :(获取VID / PID但不是驱动器号)

我有一个嵌入式设备,我通过应用程序连接到该设备。 我有代码可以成功扫描任何USB设备并检查VID/PID 。 我成功检测到我的设备,但我不知道如何获取驱动器号。 有人可以帮我吗? 我觉得我可以在class添加另一行,但是当我通过Device Manager我找不到任何描述驱动器号的属性。

谢谢!

到目前为止,我将包含我的代码。

 private void tsDownload_Click(object sender, EventArgs e) { var usbDevices = GetUSBDevices(); foreach (var usbDevice in usbDevices) { if (usbDevice.DeviceID.Contains(USB_PID) && usbDevice.DeviceID.Contains(USB_VID)) { //Find drive letter here } } } 

这些function是:

  static List GetUSBDevices() { List devices = new List(); ManagementObjectCollection collection; using (var searcher = new ManagementObjectSearcher(@"Select * From Win32_USBHub")) collection = searcher.Get(); foreach (var device in collection) { devices.Add(new USBDeviceInfo( (string)device.GetPropertyValue("DeviceID"), (string)device.GetPropertyValue("PNPDeviceID"), (string)device.GetPropertyValue("Description") )); } collection.Dispose(); return devices; } 

而且课程是:

 class USBDeviceInfo { public USBDeviceInfo(string deviceID, string pnpDeviceID, string description) { this.DeviceID = deviceID; this.PnpDeviceID = pnpDeviceID; this.Description = description; } public string DeviceID { get; private set; } public string PnpDeviceID { get; private set; } public string Description { get; private set; } } 

选项2 :(获取驱动器号但不是VID / PID)

 foreach (ManagementObject drive in new ManagementObjectSearcher("select * from Win32_DiskDrive where InterfaceType='USB'").Get()) { foreach(ManagementObject partition in new ManagementObjectSearcher("ASSOCIATORS OF {Win32_DiskDrive.DeviceID='" + drive["DeviceID"] + "'} WHERE AssocClass = Win32_DiskDriveToDiskPartition").Get()) { foreach (ManagementObject disk in new ManagementObjectSearcher("ASSOCIATORS OF {Win32_DiskPartition.DeviceID='" + partition["DeviceID"] + "'} WHERE AssocClass = Win32_LogicalDiskToPartition").Get()) { textBox1.Text = disk["Name"].ToString(); } } } 

我要猜测VID / PID是在一个disk对象属性中,但我找不到哪一个。

我可能会弄错,但似乎WMI不知道Windows设备安装API中存在的父子关系。

因此,我创建了一个小型Device实用程序类,可以从本机Setup API添加此缺少的链接。 以下是在原始USBDeviceInfo类中使用它的方法:

 class USBDeviceInfo { public USBDeviceInfo(string deviceID, string pnpDeviceID, string description) { this.DeviceID = deviceID; this.PnpDeviceID = pnpDeviceID; this.Description = description; } public string DeviceID { get; private set; } public string PnpDeviceID { get; private set; } public string Description { get; private set; } public IEnumerable GetDiskNames() { using (Device device = Device.Get(PnpDeviceID)) { // get children devices foreach (string childDeviceId in device.ChildrenPnpDeviceIds) { // get the drive object that correspond to this id (escape the id) foreach (ManagementObject drive in new ManagementObjectSearcher("SELECT DeviceID FROM Win32_DiskDrive WHERE PNPDeviceID='" + childDeviceId.Replace(@"\", @"\\") + "'").Get()) { // associate physical disks with partitions foreach (ManagementObject partition in new ManagementObjectSearcher("ASSOCIATORS OF {Win32_DiskDrive.DeviceID='" + drive["DeviceID"] + "'} WHERE AssocClass=Win32_DiskDriveToDiskPartition").Get()) { // associate partitions with logical disks (drive letter volumes) foreach (ManagementObject disk in new ManagementObjectSearcher("ASSOCIATORS OF {Win32_DiskPartition.DeviceID='" + partition["DeviceID"] + "'} WHERE AssocClass=Win32_LogicalDiskToPartition").Get()) { yield return (string)disk["DeviceID"]; } } } } } } } 

这是新的Device类:

 public sealed class Device : IDisposable { private IntPtr _hDevInfo; private SP_DEVINFO_DATA _data; private Device(IntPtr hDevInfo, SP_DEVINFO_DATA data) { _hDevInfo = hDevInfo; _data = data; } public static Device Get(string pnpDeviceId) { if (pnpDeviceId == null) throw new ArgumentNullException("pnpDeviceId"); IntPtr hDevInfo = SetupDiGetClassDevs(IntPtr.Zero, pnpDeviceId, IntPtr.Zero, DIGCF.DIGCF_ALLCLASSES | DIGCF.DIGCF_DEVICEINTERFACE); if (hDevInfo == (IntPtr)INVALID_HANDLE_VALUE) throw new Win32Exception(Marshal.GetLastWin32Error()); SP_DEVINFO_DATA data = new SP_DEVINFO_DATA(); data.cbSize = Marshal.SizeOf(data); if (!SetupDiEnumDeviceInfo(hDevInfo, 0, ref data)) { int err = Marshal.GetLastWin32Error(); if (err == ERROR_NO_MORE_ITEMS) return null; throw new Win32Exception(err); } return new Device(hDevInfo, data) {PnpDeviceId = pnpDeviceId}; } public void Dispose() { if (_hDevInfo != IntPtr.Zero) { SetupDiDestroyDeviceInfoList(_hDevInfo); _hDevInfo = IntPtr.Zero; } } public string PnpDeviceId { get; private set; } public string ParentPnpDeviceId { get { if (IsVistaOrHiger) return GetStringProperty(DEVPROPKEY.DEVPKEY_Device_Parent); uint parent; int cr = CM_Get_Parent(out parent, _data.DevInst, 0); if (cr != 0) throw new Exception("CM Error:" + cr); return GetDeviceId(parent); } } private static string GetDeviceId(uint inst) { IntPtr buffer = Marshal.AllocHGlobal(MAX_DEVICE_ID_LEN + 1); int cr = CM_Get_Device_ID(inst, buffer, MAX_DEVICE_ID_LEN + 1, 0); if (cr != 0) throw new Exception("CM Error:" + cr); try { return Marshal.PtrToStringAnsi(buffer); } finally { Marshal.FreeHGlobal(buffer); } } public string[] ChildrenPnpDeviceIds { get { if (IsVistaOrHiger) return GetStringListProperty(DEVPROPKEY.DEVPKEY_Device_Children); uint child; int cr = CM_Get_Child(out child, _data.DevInst, 0); if (cr != 0) return new string[0]; List ids = new List(); ids.Add(GetDeviceId(child)); do { cr = CM_Get_Sibling(out child, child, 0); if (cr != 0) return ids.ToArray(); ids.Add(GetDeviceId(child)); } while (true); } } private static bool IsVistaOrHiger { get { return (Environment.OSVersion.Platform == PlatformID.Win32NT && Environment.OSVersion.Version.CompareTo(new Version(6, 0)) >= 0); } } private const int INVALID_HANDLE_VALUE = -1; private const int ERROR_NO_MORE_ITEMS = 259; private const int MAX_DEVICE_ID_LEN = 200; [StructLayout(LayoutKind.Sequential)] private struct SP_DEVINFO_DATA { public int cbSize; public Guid ClassGuid; public uint DevInst; public IntPtr Reserved; } [Flags] private enum DIGCF : uint { DIGCF_DEFAULT = 0x00000001, DIGCF_PRESENT = 0x00000002, DIGCF_ALLCLASSES = 0x00000004, DIGCF_PROFILE = 0x00000008, DIGCF_DEVICEINTERFACE = 0x00000010, } [DllImport("setupapi.dll", SetLastError = true)] private static extern bool SetupDiEnumDeviceInfo(IntPtr DeviceInfoSet, uint MemberIndex, ref SP_DEVINFO_DATA DeviceInfoData); [DllImport("setupapi.dll", CharSet = CharSet.Unicode, SetLastError = true)] private static extern IntPtr SetupDiGetClassDevs(IntPtr ClassGuid, string Enumerator, IntPtr hwndParent, DIGCF Flags); [DllImport("setupapi.dll")] private static extern int CM_Get_Parent(out uint pdnDevInst, uint dnDevInst, uint ulFlags); [DllImport("setupapi.dll")] private static extern int CM_Get_Device_ID(uint dnDevInst, IntPtr Buffer, int BufferLen, uint ulFlags); [DllImport("setupapi.dll")] private static extern int CM_Get_Child(out uint pdnDevInst, uint dnDevInst, uint ulFlags); [DllImport("setupapi.dll")] private static extern int CM_Get_Sibling(out uint pdnDevInst, uint dnDevInst, uint ulFlags); [DllImport("setupapi.dll")] private static extern bool SetupDiDestroyDeviceInfoList(IntPtr DeviceInfoSet); // vista and higher [DllImport("setupapi.dll", SetLastError = true, EntryPoint = "SetupDiGetDevicePropertyW")] private static extern bool SetupDiGetDeviceProperty(IntPtr DeviceInfoSet, ref SP_DEVINFO_DATA DeviceInfoData, ref DEVPROPKEY propertyKey, out int propertyType, IntPtr propertyBuffer, int propertyBufferSize, out int requiredSize, int flags); [StructLayout(LayoutKind.Sequential)] private struct DEVPROPKEY { public Guid fmtid; public uint pid; // from devpkey.h public static readonly DEVPROPKEY DEVPKEY_Device_Parent = new DEVPROPKEY { fmtid = new Guid("{4340A6C5-93FA-4706-972C-7B648008A5A7}"), pid = 8 }; public static readonly DEVPROPKEY DEVPKEY_Device_Children = new DEVPROPKEY { fmtid = new Guid("{4340A6C5-93FA-4706-972C-7B648008A5A7}"), pid = 9 }; } private string[] GetStringListProperty(DEVPROPKEY key) { int type; int size; SetupDiGetDeviceProperty(_hDevInfo, ref _data, ref key, out type, IntPtr.Zero, 0, out size, 0); if (size == 0) return new string[0]; IntPtr buffer = Marshal.AllocHGlobal(size); try { if (!SetupDiGetDeviceProperty(_hDevInfo, ref _data, ref key, out type, buffer, size, out size, 0)) throw new Win32Exception(Marshal.GetLastWin32Error()); List strings = new List(); IntPtr current = buffer; do { string s = Marshal.PtrToStringUni(current); if (string.IsNullOrEmpty(s)) break; strings.Add(s); current += (1 + s.Length) * 2; } while (true); return strings.ToArray(); } finally { Marshal.FreeHGlobal(buffer); } } private string GetStringProperty(DEVPROPKEY key) { int type; int size; SetupDiGetDeviceProperty(_hDevInfo, ref _data, ref key, out type, IntPtr.Zero, 0, out size, 0); if (size == 0) return null; IntPtr buffer = Marshal.AllocHGlobal(size); try { if (!SetupDiGetDeviceProperty(_hDevInfo, ref _data, ref key, out type, buffer, size, out size, 0)) throw new Win32Exception(Marshal.GetLastWin32Error()); return Marshal.PtrToStringUni(buffer); } finally { Marshal.FreeHGlobal(buffer); } } } 

我有同样的问题,浏览WMI并没有帮助我,真的。

但我最终得到了这几行代码,它对我很有用:

 private string GetAvailableStorageDrive() { foreach (var info in System.IO.DriveInfo.GetDrives()) { if (info.DriveType == System.IO.DriveType.Removable && info.IsReady && !info.Name.Equals("A:\\")) { return info.Name; } } return string.Empty; } 

基本上,上面的函数查看DriveType是否Removable以及Drive是否准备就绪。 我还排除了驱动器号’A’,因为在默认的Windows环境中,这是软盘。

DriveType.Removable的描述:

该驱动器是可移动存储设备,例如软盘驱动器或USB闪存驱动器。

注意:正如CodeCaster所指出的,此function还将返回可移动存储设备,如SATA。 因此,如果是这种情况,您将不得不研究其他人提供的更复杂的解决方案。

有一个古老的Win32 API用于设备枚举,它曾经是安装程序API的一部分但已经废弃 – 我只知道它的存在,不是它的用法,但希望它会有所帮助:

http://msdn.microsoft.com/en-us/library/windows/hardware/ff551015(v=vs.85).aspx

SP_DEVICE_INTERFACE_DETAIL结构是您的最终目标:它具有实际的设备路径。 然而,到达那里的路径……它都是PInvoke,从签名看起来相当讨厌,但这里有一些参考:

PInvoke签名:

http://pinvoke.net/default.aspx/setupapi/SetupDiGetClassDevs.html http://pinvoke.net/default.aspx/setupapi/SetupDiEnumDeviceInterfaces.html http://pinvoke.net/default.aspx/setupapi/SetupDiGetDeviceInterfaceDetail。 HTML

结构映射:

http://pinvoke.net/default.aspx/Structures/SP_DEVICE_INTERFACE_DATA.html http://pinvoke.net/default.aspx/Structures/SP_DEVICE_INTERFACE_DETAIL_DATA.html

哦,我发现了一些示例用法(在C ++中,但可以翻译):

http://oroboro.com/usb-serial-number/