问题描述
所以我想我会在这里包含最终答案,这样你就不必理解这篇文章了.非常感谢 Simon Mourier 抽出时间解决这个问题.
So I thought I would include the final answer here so you don't have to make sense of this post. Big thanks to Simon Mourier for taking the time to figure this one out.
我的工作代码
try
{
//Get a list of available devices attached to the USB hub
List<string> disks = new List<string>();
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 的答案中显示的两个类,就可以了!
So just use GetUSBDevices
from my original question and then include the two classes shown by Simon Mourier's answer and it should be good to go!
原始问题
我知道之前有人问过这个问题(参见 here)但他们都没有得到确认的答案,我已经尝试了所有建议的答案.不幸的是,这些线程早已死了,我希望有人能在这里给出更好的答案.
I know this question has been asked before (see here) but none of them have a confirmed answer and I've tried all of the suggested answers. Unfortunately those threads are long dead and I was hoping someone could give a better answer here.
到目前为止,我有两个起点",我将在下面展示每一个.
So far I have two 'starting points', each of which I'll show below.
选项 1:(获取 VID/PID 但不获取驱动器号)
OPTION 1: (gets VID/PID but not drive letter)
我有一个通过应用程序连接的嵌入式设备.我有成功扫描任何 USB 设备并检查 VID/PID
的代码.我成功检测到我的设备,但我不知道如何获取驱动器号.有人可以帮我吗?我觉得我可以在 class
中添加另一行,但是当我浏览 Device Manager
时,我找不到任何描述驱动器号的属性.
I have an embedded device which I connect to through an application. I have code which succesfully scans any USB devices and checks the VID/PID
. I successfully detect my device but I have no idea how to get the drive letter. Can someone help me out? I feel like I could add another line in the class
but when I go through Device Manager
I can't find any property there that describes the drive letter.
谢谢!
我将在下面包含我的代码.
I'll include my code so far below.
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
}
}
}
这些函数在哪里:
static List<USBDeviceInfo> GetUSBDevices()
{
List<USBDeviceInfo> devices = new List<USBDeviceInfo>();
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)
OPTION 2: (get drive letter but not 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
对象属性之一中,但我就是找不到哪个.
I'm going to guess the VID/PID is in one of the disk
object properties but I just can't find which one.
推荐答案
我可能搞错了,但 WMI 似乎不知道 Windows 设备设置 API 中存在的父子关系.
I may be mistaken but it seems WMI doesn't know about the parent-child relation that exists in the Windows device setup API.
因此,我创建了一个小的 Device
实用程序类,它可以从本机设置 API 添加这个缺失的链接.以下是您在原始 USBDeviceInfo
类中的使用方法:
So, I have created a small Device
utility class that can add this missing link from the native Setup API. Here is how you would use it in your original USBDeviceInfo
class:
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<string> 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"];
}
}
}
}
}
}
}
这是新的设备类:
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<string> ids = new List<string>();
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<string> strings = new List<string>();
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);
}
}
}
这篇关于从 VID/PID 中查找 USB 驱动器号(XP 及更高版本需要)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!