I'm trying to create a piece of software that can save a USB device's info, such as: Name, Total Space, Free Space, Format Type, etc. I've used DriveInfo[] but I can't work out how to save each INDIVIDUAL piece for different USB devices separately, so I know which USB device applies to what info. I'm trying to save each USB device and it's info to a text file. Here's what I have:
DriveInfo[] loadedDrives = DriveInfo.GetDrives();
foreach (DriveInfo ld in loadedDrives)
{
if (ld.DriveType == DriveType.Removable)
{
if (ld.IsReady == true)
{
deviceInfo.Add(ld.VolumeLabel + ": , " + ld.TotalSize + ": , " + ld.AvailableFreeSpace + ": , " + ld.DriveFormat);
}
}
}
foreach (String st in deviceInfo)
{
string[] deviceSel;
// DriveInfo dInfo;
deviceSel = st.Split(splitChar);
if (itemSelected.Contains(deviceSel[0]))
{
//Check That USB drive is the one thats selected
MessageBox.Show(deviceSel[0]);
break;
}
}
Is there an easier way than what I've done? Because the further I try and solve the problem, the more complex the code gets. Cheers
Ok, you don't need to put into an array of string, keep them as DriveInfo:
DriveInfo[] loadedDrives = DriveInfo.GetDrives();
List<DriveInfo> deviceInfo = new List<DriveInfo>();
foreach (DriveInfo ld in loadedDrives)
{
if (ld.DriveType == DriveType.Removable)
{
if (ld.IsReady == true)
{
deviceInfo.Add(ld);
}
}
}
foreach (DriveInfo st in deviceInfo)
{
//can write whatever you want now
}
But that first loop can be done a lot easier with linq:
DriveInfo[] loadedDrives = DriveInfo.GetDrives();
var deviceInfo = DriveInfo.GetDrives()
.Where(d=>d.DriveType == DriveType.Removable && d.IsReady);
Related
This form of ManagementObject (using ".DeviceID=") assignment works:
// get number of logical drives on given physical disk
int n = 0;
var id = "\\\\.\\PHYSICALDRIVE0";
var disk = new ManagementObject("Win32_DiskDrive.DeviceID=" + "'" + id + "'");
foreach (ManagementObject dp in disk.GetRelated("Win32_DiskPartition"))
{
foreach (ManagementObject ld in dp.GetRelated("Win32_LogicalDisk")) ++n;
}
This form of ManagementObject (using ".Number=") assignment fails:
// get number of logical drives on given physical disk
int n = 0;
var id = "0";
ManagementObject disk = new ManagementObject("root\\Microsoft\\Windows\\Storage:MSFT_Disk.Number=" + "'" + id + "'");
foreach (ManagementObject dp in disk.GetRelated("MSFT_Partition"))
{
foreach (ManagementObject ld in dp.GetRelated("MSFT_Volume")) ++n;
}
The exception is "Invalid object path". I have spent an embarrassing amount of time trying to figure out what I am doing wrong...and have no clue.
The specific item being searched for here is not the relevant issue. The proper syntax of using the two statements is what I am trying to understand...
The path for the working case is: "root\CIMV2" and the path to the failing case is: "root\Microsoft\Windows\Storage".
The failing statement is: "foreach (ManagementObject dp in disk.GetRelated("MSFT_Partition"))"
#user9938: I appreciate your reply and the focus on the MSFT_xxx items. I was looking for an analogous syntax solution to the Win32_xxx approach.
After considerable trial and error, it appears that the approach of assigning the specific disk directly in the ManagementObject declaration statement is simply not supported when using MSFT_Disk.
Either of these two statements work correctly:
var disk = new ManagementObject("Win32_DiskDrive=
var disk = new ManagementObject("Win32_DiskDrive.DeviceID=
There does not appear to be any analogous statement when using MSFT_Disk.
Thus, the simplest code solution is:
var phy = "0"; // ... or any valid disk index
int num = 0;
var disk = new ManagementObject("Win32_DiskDrive='\\\\.\\PHYSICALDRIVE" + phy + "'");
foreach (ManagementObject dp in disk.GetRelated("Win32_DiskPartition"))
{
foreach (ManagementObject ld in dp.GetRelated("Win32_LogicalDisk")) ++num;
}
There are a number of ways to retrieve the information. Try the following instead:
private int GetNumberOfLogicalDrives(int number)
{
int numLogicalDrives = 0;
using (ManagementObjectSearcher searcher = new ManagementObjectSearcher(new ManagementScope(#"root\Microsoft\Windows\Storage"), new SelectQuery($"SELECT * FROM MSFT_Disk WHERE Number = {number}")))
{
using (ManagementObjectCollection logicalDrives = searcher.Get())
{
if (logicalDrives != null && logicalDrives.Count > 0)
{
foreach (ManagementObject mObj in logicalDrives)
{
//re-initialize
numLogicalDrives = 0;
if (mObj == null)
continue;
foreach (ManagementObject mObjDP in mObj.GetRelated("MSFT_Partition"))
{
if (mObjDP == null)
continue;
foreach (ManagementObject mObjLD in mObjDP.GetRelated("MSFT_Volume"))
{
if (mObjLD == null)
continue;
//skip if there isn't a drive letter
if (String.IsNullOrEmpty(mObjLD["DriveLetter"]?.ToString().Trim()))
continue;
numLogicalDrives++; //increment
}
}
Debug.WriteLine($"number: {number}; numLogicalDrives: {numLogicalDrives}");
}
}
}
}
return numLogicalDrives;
}
Usage:
int numLogicalDrives = GetNumberOfLogicalDrives(0);
Resources:
System.Management
I am trying to show the vid/pid and the drive letter of a usb drive when I connect it to my computer. I'm actually able to do both, but not at the same time.
1: I can use Win32_DiskDrive to get to Win32_LogicalDisk and extract the drive letter. But the deviceId has a non-numerical pid/vid which I can't use.
2: I can use Win32_USBHub or Win32_PnPEntity to extract the vid/pid, but I can't find a link between them and the drive letter.
public void CheckForUsbDevice()
{
string text =
"SELECT * FROM __InstanceCreationEvent " +
"WITHIN 2 "
+ "WHERE TargetInstance ISA 'Win32_PnPEntity'";
ManagementEventWatcher watcher = new ManagementEventWatcher();
WqlEventQuery query = new WqlEventQuery(text);
watcher.EventArrived += new EventArrivedEventHandler(watcher_EventArrived);
watcher.Query = query;
watcher.Start();
Console.ReadKey();
}
static readonly Guid GUID_DEVCLASS_USB = new Guid("{36fc9e60-c465-11cf-8056-444553540000}");
static void watcher_EventArrived(object sender, EventArrivedEventArgs e)
{
ManagementBaseObject instance = (ManagementBaseObject)e.NewEvent["TargetInstance"];
if ((new Guid((string)instance["ClassGuid"]) == GUID_DEVCLASS_USB) && ((string)instance.Properties["Name"].Value == "USB Mass Storage Device"))
{
// we're only interested by USB devices, dump all props
foreach (var property in instance.Properties)
{
Console.WriteLine(property.Name + " = " + property.Value);
}
}
}
This has the output:
Availability =
Caption = USB Mass Storage Device
ClassGuid = {36fc9e60-c465-11cf-8056-444553540000}
CompatibleID = System.String[]
ConfigManagerErrorCode = 0
ConfigManagerUserConfig = False
CreationClassName = Win32_PnPEntity
Description = USB Mass Storage Device
DeviceID = USB\VID_0911&PID_1F40&MI_00\6&27CAD51B&0&0000
ErrorCleared =
ErrorDescription =
HardwareID = System.String[]
InstallDate =
LastErrorCode =
Manufacturer = Compatible USB storage device
Name = USB Mass Storage Device
PNPClass = USB
PNPDeviceID = USB\VID_0911&PID_1F40&MI_00\6&27CAD51B&0&0000
PowerManagementCapabilities =
PowerManagementSupported =
Present = True
Service = USBSTOR
Status = OK
StatusInfo =
SystemCreationClassName = Win32_ComputerSystem
SystemName = WINDEV1905EVAL
I need a link between WMI classed containing the numerical pid/vid and the drive letter or a different way how that can be achieved.
I think it might be possible to use DeviceIoControl, but I have no idea where to start there.
Any help is highly appreciated.
Here is a part of a simple web page to show a selector list of the available log files on an attached drive:
public void OnGet()
{
StringBuilder logContent = new StringBuilder();
string[] files = null;
string directory = #"Q:\logs";
string reason = "Undefined";
try
{
files = Directory.GetFiles(directory, "*.csv");
}
catch (Exception ex)
{
reason = ex.Message;
}
if (files != null && files.Length > 0)
{
logContent.Append(#"<select>");
foreach (string file in files)
{
string aFile = file.Substring(file.LastIndexOf(Path.DirectorySeparatorChar) + 1);
logContent.Append("<option value=\"" + aFile + "\">" + aFile + "</option>");
}
logContent.Append(#"</select>");
...
else
{
logContent.Append("<h3>An Exception occurred: " + reason + "</h3>");
}
Message = logContent.ToString();
}
When the page runs, I get the exception
"Cannot find a part of the path Q:\logs.
The drive is there and if I do a dir Q:\logs in the command prompt from C drive it displays the contents.
What am I missing here?
What are you using IIS?
If so, then the user that is running the application (application pool in IIS) has to be you. Otherwise, you need to map the drive for that user, since it sounds like Q is a network mapped drive.
I'm trying to find a particular USB device (1 or more) connected to my computer and retrieve the relevant path to the mounted drive. Ideally, it would be by finding the VID/PID of the USB device, but I'm not sure how to do that yet. The following works, but there must be some way to get the data in a single query.
What I'm doing here is looking or a physical drive that has a model matching HS SD Card Bridge USB Device and finding the physical drive # associated and using that to find the mounted partition..
foreach (ManagementObject disk in disks.Get()) {
//look for drives that match our string
Match m = Regex.Match(disk["model"].ToString(), "HS SD Card Bridge USB Device");
if (m.Success) {
m = Regex.Match(disk["DeviceID"].ToString(), #"PHYSICALDRIVE(\d+)");
if (m.Success) {
int driveNumber = Int32.Parse(m.Groups[1].ToString());
ManagementObjectSearcher mapping = new ManagementObjectSearcher("SELECT * FROM Win32_LogicalDiskToPartition");
foreach (ManagementObject map in mapping.Get()) {
m = Regex.Match(map["Antecedent"].ToString(), #"Disk #" + driveNumber + ",");
if (m.Success) {
string drive = map["Dependent"].ToString();
m = Regex.Match(drive, #"([A-Z]):");
if (m.Success) {
drive = m.Groups[1].ToString(); //< -- **FOUND**
}
}
}
//USBDevice dev = new USBDevice("", "");
// list.Items.Add();
Console.WriteLine("");
}
}
}
is there a way to do this from the VID/PID and a way to construct the search query so it requires just one query?
This is the one I used earlier . This will not be the answer. But will help you .
public int GetAvailableDisks()
{
int deviceFound = 0;
try
{
// browse all USB WMI physical disks
foreach (ManagementObject drive in
new ManagementObjectSearcher(
"select DeviceID, Model from Win32_DiskDrive where InterfaceType='USB'").Get())
{
ManagementObject partition = new ManagementObjectSearcher(String.Format(
"associators of {{Win32_DiskDrive.DeviceID='{0}'}} where AssocClass = Win32_DiskDriveToDiskPartition",
drive["DeviceID"])).First();
if (partition == null) continue;
// associate partitions with logical disks (drive letter volumes)
ManagementObject logical = new ManagementObjectSearcher(String.Format(
"associators of {{Win32_DiskPartition.DeviceID='{0}'}} where AssocClass = Win32_LogicalDiskToPartition",
partition["DeviceID"])).First();
if (logical != null)
{
// finally find the logical disk entry to determine the volume name - Not necesssary
//ManagementObject volume = new ManagementObjectSearcher(String.Format(
// "select FreeSpace, Size, VolumeName from Win32_LogicalDisk where Name='{0}'",
// logical["Name"])).First();
string temp = logical["Name"].ToString() + "\\";
// +" " + volume["VolumeName"].ToString(); Future purpose if Device Name required
deviceFound++;
if (deviceFound > 1)
{
MessageBox.Show(#"Multiple Removeable media found. Please remove the another device");
deviceFound--;
}
else
{
driveName = temp;
}
}
}
}
catch (Exception diskEnumerateException)
{
}
return deviceFound;
}
The following code returns only three serial ports (com3, com4 and com5). The firmware that I would like to access is located on a USB plug multiplier. How can I access the serial ports of this mulitplier and how can I identify the specific USB containing the firmware that I want to send information to?
using System;
using System.IO.Ports;
namespace SerialPortExample
{
class SerialPortExample
{
public static void Main()
{
string[] ports = SerialPort.GetPortNames();
Console.WriteLine("The following serial ports were found:");
foreach (string port in ports)
{
Console.WriteLine(port);
}
Console.ReadLine();
}
}
}
Many thanks in advance!
This is a pretty big usability problem and caused by USB drivers taking a shortcut and emulating a serial port to make it easy to interface with them. Serial ports are very primitive devices, which makes their api very easy to use. But lacks any kind of support for plug-and-play, there's no way to get a decent notification for them. The driver just picks an arbitrary port number and it is up to the user to figure out which one it might be. Trial and error stuff. This didn't use to be a problem, serial ports had a connector mounted on the machine's back panel that was clearly labeled with the COM port name.
You can possibly get some mileage out of WMI, it lets you enumerate serial port devices with the Win32_SerialPort query. What you get is fairly unpredictable, it completely depends on the driver to supply the data. Best way to experiment with that is with the WMI Code Creator utility, it can also auto-generate the C# code you need. Unfortunately I can't find the download location anymore, this appears to have been removed in the past couple of weeks. Hope you can find an alternative.
The code below does a good job finding the specific ports:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Management;
using System.Windows.Forms;
namespace MyNamespace
{
class Program
{
static void Main(string[] args)
{
MyClass x = new MyClass();
var com = x.GetCOMs();
foreach (string port in com)
{
Console.WriteLine(port);
}
Console.ReadLine();
}
}
class MyClass
{
public List<string> GetCOMs()
{
List<string> coms = new List<string>();
try
{
ManagementObjectSearcher searcher = new ManagementObjectSearcher("root\\CIMV2",
"SELECT * FROM Win32_PnPEntity WHERE ConfigManagerErrorCode = 0");
foreach (ManagementObject obj in searcher.Get())
{
object captionObj = obj["Caption"];
if (captionObj != null)
{
string caption = captionObj.ToString();
if (caption.Contains("(COM"))
{
coms.Add(caption);
}
}
}
m_ParseCOMs(ref coms);
}
catch (ManagementException ex)
{
MessageBox.Show("An error occurred while querying for WMI data: " + ex.Message);
return coms;
}
return coms;
}
private void m_ParseCOMs(ref List<string> comPorts)
{
string[] temp;
List<string> temp2 = new List<string>();
int index = 0;
foreach (string s in comPorts)
{
string temp3 = "";
temp = s.Split(' ');
temp3 += temp[temp.Length - 1] + " - ";
for (int i = 0; i < temp.Length - 1; i++)
{
temp3 += temp[i] + " ";
}
temp2.Insert(index, temp3);
index++;
}
comPorts = temp2;
}
}
}