Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get drive label in C#

Tags:

c#

drive

When I use System.IO.DriveInfo.GetDrives() and look at the .VolumeLabel property of one of the drives, I see "PATRIOT XT", which is indeed the drive's volume label.

If I open "My Computer", instead I see "TrueCrypt Traveler Disk", and I can't seem to find any way to programmatically retrieve that value as none of the DriveInfo properties hold that value. I also tried querying the information via WMI's Win32_LogicalDisk, but no properties contained that value there either.

So any idea what the label My Computer uses is called, and more importantly, how to programmatically retrieve it?

EDIT: To be clear, here's the code I'm using, followed by what it outputs, followed by what I see in My Computer (which is what I want to duplicate):

foreach (DriveInfo DI in DriveInfo.GetDrives())
    richTextBox1.AppendText(
        (
            DI.IsReady ?
            (DI.VolumeLabel.Length == 0 ? DI.DriveType.ToString() : DI.VolumeLabel) :
            DI.DriveType.ToString()
        )
        +
        " (" + DI.Name.Replace("\\", "") + ")"
        + Environment.NewLine
    );
Removable (A:)
Fixed (C:)
CDRom (D:)
PATRIOT XT (E:)
Backup (Y:)
Data (Z:)

My Computer details view displays:

Floppy Disk Drive (A:)
Local Disk (C:)
DVD RW Drive (D:)
TrueCrypt Traveler Disk (E:)
Backup (Y:)
Data (Z:)
like image 596
Rick Avatar asked May 16 '10 13:05

Rick


People also ask

What is current volume label for drive C?

As you can see, the volume label for the C drive is Windows and the volume serial number is C1F3-A79E.

How do you label a drive?

Right-click the drive you want to rename. In the drop-down menu that appears, select Properties. In the Properties window, on the General tab, type a new name in the Label box (A), click Apply (B), and then click OK (C).

What is the label for volume?

A volume label, sometimes called a volume name, is a unique name assigned to a hard drive, disc, or other media. It's not required in Windows, but it's often useful to give a name to a drive to help identify its use in the future.


1 Answers

Unfortunately, to get this information without hacks and weird tricks, you need to use the P/Invoke technique. There are 2 options:

  1. Get the real label set by user or system. This could be "New volume", "Install (\Server)", "Contoso Pro Installation disk 4" and so on.
  2. Get the label exactly as it is shown in Explorer (My computer / This PC window). This is the same as (1) but it follows user preferences set in Folder Options dialog, e.g. "Hide drive letter". Example: "New volume (Q:)"

To get the information as explained in option (1), you'll have to use the following code:

    public const string SHELL = "shell32.dll";

    [DllImport(SHELL, CharSet = CharSet.Unicode)]
    public static extern uint SHParseDisplayName(string pszName, IntPtr zero, [Out] out IntPtr ppidl, uint sfgaoIn, [Out] out uint psfgaoOut);
    
    [DllImport(SHELL, CharSet = CharSet.Unicode)]
    public static extern uint SHGetNameFromIDList(IntPtr pidl, SIGDN sigdnName, [Out] out String ppszName);
    
    public enum SIGDN : uint
    {
        NORMALDISPLAY = 0x00000000,
        PARENTRELATIVEPARSING = 0x80018001,
        DESKTOPABSOLUTEPARSING = 0x80028000,
        PARENTRELATIVEEDITING = 0x80031001,
        DESKTOPABSOLUTEEDITING = 0x8004c000,
        FILESYSPATH = 0x80058000,
        URL = 0x80068000,
        PARENTRELATIVEFORADDRESSBAR = 0x8007c001,
        PARENTRELATIVE = 0x80080001
    }
    
    //var x = GetDriveLabel(@"C:\")
    public string GetDriveLabel(string driveNameAsLetterColonBackslash)
    {
        IntPtr pidl;
        uint dummy;
        string name;
        if (SHParseDisplayName(driveNameAsLetterColonBackslash, IntPtr.Zero, out pidl, 0, out dummy) == 0
            && SHGetNameFromIDList(pidl, SIGDN.PARENTRELATIVEEDITING, out name) == 0
            && name != null)
        {
            return name;
        }
        return null;
    }

For option (2), replace SIGDN.PARENTRELATIVEEDITING with SIGDN.PARENTRELATIVE or SIGDN.NORMALDISPLAY.

Note: for option 2, there's also 1-call method using ShGetFileInfo(), but it calls these methods anyway, and is less flexible, so I do not post it here.

Note 2: keep in mind, the signature of SHGetNameFromIDList() is optimized in this example. In case the drive label is used only temporary (especially if it is re-read from time to time) this example introduces small memory leak. To avoid it, declare last parameter as out IntPtr, and then use something like

     var tmp = Marshal.PtrToStringUni(ppszName);
     Marshal.FreeCoTaskMem(ppszName);

Note 3: this works over Windows shell, so it will return what user expects, regardless of the source of this label - volume label, user edit, Autorun.inf file or anything else.

like image 136
Mike Makarov Avatar answered Sep 23 '22 17:09

Mike Makarov