27 September, 2006

Getting Disk Information in C#

Using System.Management and Win32_LogicalDisk


In my last post, I briefly spoke about finding drive information in a C# application. The problem I've been trying to solve is that I have a windows form that needs to run at the end of an install. The form allows the user to copy files from a specific location on the install DVD to the users machine. The files are about 1.3Gb, and I didn't really want to package all that data into one MSI file. A problem arose when the install was finished, and the little windows application was copied to the user's machine, how can I find the DVD drive? And after I found a DVD drive, how can I make certain it is the correct drive with the correct disk?

I started out by importing the kernel32.dll and using the external GetDriveType(string drive). This worked, but I was really wanting to find a C# way to do this without having to import anything else. Enter System.Management - which allows a user to get all of this information natively in C# using Win32_LogicalDisk. Win32_LogicalDisk give you access to a plethora of information on all physical and mapped network drives. You can get the drive name, device id, volume name, serial number and on and on. In addition, you can run SQL type queries against the drive to get just the desired information from the desired drives or drive types or drive sizes and so forth.

Since I am interested in finding CD/DVD drives, I had to find how to tell what kind of drive I was looking at. The following (from the above linked MSDN page) table was a great help:
























Value
Meaning
0
Unknown
1
No Root Directory
2
Removeable Disk
3
Local Disk
4
Network Drive
5
Compact Disc
6
RAM Disk

Using System.Management.ManagementObjectCollection and System.Management.ManagementObjectSearcher I was able to create a collection of all drives with a device type of 5.

ManagementScope ms = new ManagementScope();
ObjectQuery oq = new ObjectQuery("SELECT DeviceID, VolumeName FROM Win32_LogicalDisk WHERE DriveType= 5");
ManagementObjectSearcher mos = new ManagementObjectSearcher(ms,oq);
ManagementObjectCollection moc = mos.Get();


Then I loop through the collection to check out each object's information:

foreach (ManagementObject mo in moc)
{
if (string.Compare(mo["VolumeName"].ToString(),"myString",true) == 0)
DirectoryInfo newDI = new DirectoryInfo(System.IO.Path.Combine(mo["DeviceID"].ToString(), "myPath"));
}

(thanks Shawn, for pointing out the error where I tried to get the volume name from the ManagementObjectCollection, instead of the ManagementObject. While here, I thought I'd go ahead and do the string comparison correctly too. :) )

So now I have what should be the proper path to the files I want to install.

Another route to this information is via the ManagementClass class. It is a little cleaner, and a bit quicker to code, but does give you more than you might need for your particular purpose.

ManagementClass mc = new ManagementClass("Win32_LogicalDisk");
ManagementObjectCollection moc = mc.getInstances();
foreach (ManagementObject mo in moc)
{
// Your code here
}


Few less lines of code, but a much more generic return on the drive information.

3 comments:

Anonymous said...

in your second code block, the line here:

if (moc["VolumeName"].ToString() == "myString")

should actually be

if (mo["VolumeName"].ToString() == "myString")

which I think is your intention. the moc object isn't indexable, i got a compiler error when using the code as it is

Unknown said...

You are entirely correct Shawn, thanks for catching that. I'll fix it in the post directly.

Chizl said...

DriveType = 5 is for CDRoms, so it should be DriveType = 3. Some CDRoms do not have VolumeName and errors in your code. Should just use Name, since not everyone is going to use the Same VolumeName for C: Drive.