Znajdź literę dysku USB z VID / PID (potrzebne dla XP i wyższych)
Więc pomyślałem, że dołączę tutaj ostateczną odpowiedź, abyś nie musiał rozumieć tego postu. Wielkie podziękowania dla Simona Mouriera za poświęcenie czasu na rozgryzienie tego.
MÓJ KODEKS PRACY
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();
}
}
}
Więc po prostu użyj GetUSBDevices
z mojego oryginalnego pytania, a następnie dołącz dwie klasy pokazane przez odpowiedź Simona Mouriera i powinno być dobrze!
ORYGINALNE PYTANIE
Wiem, że to pytanie zostało zadane wcześniej (patrz tutaj ) ale żadna z nich nie ma potwierdzonej odpowiedzi i próbowałem wszystkich sugerowanych odpowiedzi. Niestety te wątki są już dawno martwe i miałem nadzieję, że ktoś da tutaj lepszą odpowiedź.
Do tej pory mam dwa "punkty wyjścia", z których każdy pokażę poniżej.
Opcja 1 : (pobiera VID/PID, ale nie literę napędu)
Mam wbudowane urządzenie, do którego podłączam się za pomocą aplikacji. Mam kod który z powodzeniem skanuje wszelkie Urządzenia USB i sprawdza VID/PID
. Z powodzeniem wykrywam moje urządzenie, ale nie mam pojęcia, jak uzyskać literę dysku. Czy ktoś może mi pomóc? Wydaje mi się, że mógłbym dodać kolejną linijkę w class
, ale kiedy przechodzę przez Device Manager
, nie mogę znaleźć tam żadnej właściwości opisującej literę dysku.
Dzięki!
Dołączę mój kod do tej pory poniżej.
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
}
}
}
Gdzie te funkcje to:
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;
}
A Klasa to:
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; }
}
Opcja 2: (Pobierz dysk litera ale nie 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();
}
}
}
Zgadnę, że VID / PID znajduje się w jednej z właściwości obiektu disk
, ale nie mogę znaleźć, która z nich.
3 answers
Mogę się mylić, ale wydaje się, że WMI nie wie o relacji rodzic-dziecko, która istnieje w interfejsie API konfiguracji urządzeń systemu Windows.
Dlatego utworzyłem małą klasę narzędzi Device
, która może dodać brakujące łącze z natywnego API konfiguracji. Oto jak byś go użył w swojej oryginalnej klasie 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<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"];
}
}
}
}
}
}
}
A oto nowa klasa urządzenia:
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);
}
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-04 08:06:53
Miałem ten sam problem i również przeglądanie WMI nie pomogło mi, naprawdę.
Ale skończyło się na tych kilku linijkach kodu, i działa świetnie dla mnie:
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;
}
Zasadniczo powyższa funkcja wygląda, jeśli DriveType
jest Removable
oraz jeśli napęd jest gotowy.
Wykluczam również literę dysku "A", ponieważ w domyślnych środowiskach windows jest to dyskietka.
Opis typu napędu."Removable": {]}
dysk jest wymiennym urządzeniem pamięci masowej, takim jak dyskietki lub pendrive ' a.
Uwaga: Jak zauważył CodeCaster, funkcja ta zwróci również wymienne urządzenia pamięci masowej, takie jak SATA. Więc jeśli tak jest, będziesz musiał przyjrzeć się bardziej złożonym rozwiązaniom dostarczanym przez innych.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-03 17:22:15
Istnieje starożytne API Win32 do wyliczania urządzeń, kiedyś było częścią API instalatora, ale popadło w nieużywanie - jestem tylko świadomy jego istnienia, a nie jego użycia, ale mam nadzieję, że będzie pomocne: {]}
Http://msdn.microsoft.com/en-us/library/windows/hardware/ff551015 (v=vs.85). aspx
Struktura SP_DEVICE_INTERFACE_DETAIL
jest twoim celem końcowym: ma rzeczywistą ścieżkę urządzenia. Jednak droga, aby się tam dostać... To wszystko byłoby PInvoke, i dość paskudne patrząc z podpisów, ale oto kilka odniesień:
Sygnatury 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
Struktura "mappings": {]}
Http://pinvoke.net/default.aspx/Structures/SP_DEVICE_INTERFACE_DATA.html http://pinvoke.net/default.aspx/Structures/SP_DEVICE_INTERFACE_DETAIL_DATA.html
Ooh, znalazłem jakiś przykład użycia (w C++, ale dość tłumaczalne):
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-03 17:28:45