Получить метку диска в С#
Когда я использую System.IO.DriveInfo.GetDrives()
и смотрю на свойство .VolumeLabel
одного из дисков, я вижу "PATRIOT XT", который действительно является меткой объема диска.
Если я открою "Мой компьютер", вместо этого я увижу "TrueCrypt Traveler Disk", и я не могу найти способ программного получения этого значения, поскольку ни одно из свойств DriveInfo
не удерживает это значение. Я также попробовал запросить информацию через WMI Win32_LogicalDisk
, но никакие свойства не содержали этого значения.
Итак, любая идея, которую использует метка My Computer, и что еще более важно, как ее программно получить?
РЕДАКТИРОВАТЬ: Чтобы быть ясным, здесь используется код, который я использую, за которым следует то, что он выводит, а затем то, что я вижу в "Моем компьютере" (это то, что я хочу дублировать):
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:)
Отобразится окно просмотра сведений о компьютере:
Floppy Disk Drive (A:)
Local Disk (C:)
DVD RW Drive (D:)
TrueCrypt Traveler Disk (E:)
Backup (Y:)
Data (Z:)
Ответы
Ответ 1
К сожалению, чтобы получить эту информацию без хаков и странных трюков, вам нужно использовать технику P/Invoke.
Есть 2 варианта:
- Получить реальную метку, установленную пользователем или системой. Это могут быть "Новый том", "Установить (\ Сервер)", "Установочный диск Contoso Pro 4" и т.д.
- Получить метку точно так, как она показана в Проводнике (Мой компьютер/Это окно ПК). Это то же самое, что и (1), но оно следует за настройками пользователя, заданными в диалоговом окне "Параметры папки", например. "Скрыть букву диска". Пример: "Новый том (Q:)"
Чтобы получить информацию, как описано в опции (1), вам нужно будет использовать следующий код:
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;
}
Для опции (2) замените SIGDN.PARENTRELATIVEEDITING
на SIGDN.PARENTRELATIVEEDITING
или SIGDN.NORMALDISPLAY
.
Примечание: для опции 2 также существует метод 1-вызова с использованием ShGetFileInfo()
, но он все равно вызывает эти методы и менее гибкий, поэтому я не размещаю его здесь.
Примечание 2: имейте в виду, что в этом примере оптимизирована подпись SHGetNameFromIDList()
. В случае, если метка привода используется только временная (особенно, если она перечитывается время от времени), этот пример вводит небольшую утечку памяти. Чтобы избежать этого, объявите последний параметр как out IntPtr
, а затем используйте что-то вроде
var tmp = Marshal.PtrToStringUni(ppszName);
Marshal.FreeCoTaskMem(ppszName);
Примечание 3. Это работает над оболочкой Windows, поэтому она вернет то, что ожидает пользователь, независимо от источника этой метки - метки тома, редактирования пользователя, файла Autorun.inf или всего остального.
Ответ 2
Спасибо за отзыв о autorun.inf. Вот фрагмент С#, который я создал для извлечения метки.
private string GetDriveLabelFromAutorunInf(string drivename)
{
try
{
string filepathAutorunInf = Path.Combine(drivename, "autorun.Inf");
string stringInputLine = "";
if (File.Exists(filepathAutorunInf))
{
StreamReader streamReader = new StreamReader(filepathAutorunInf);
while ((stringInputLine = streamReader.ReadLine()) != null)
{
if (stringInputLine.StartsWith("label="))
return stringInputLine.Substring(startIndex:6);
}
return "";
}
else return "";
}
#region generic catch exception, display message box, and terminate
catch (Exception exception)
{
System.Diagnostics.StackTrace trace = new System.Diagnostics.StackTrace(exception, true);
MessageBox.Show(string.Format("{0} Exception:\n{1}\n{2}\n\n{3}\n\nMethod={4} Line={5} Column={6}",
trace.GetFrame(0).GetMethod().Module,
exception.Message,
exception.StackTrace,
exception.ToString(),
trace.GetFrame(0).GetMethod().Name,
trace.GetFrame(0).GetFileLineNumber(),
trace.GetFrame(0).GetFileColumnNumber()),
"Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
Environment.Exit(1);
return ""; // to keep compiler happy
}
#endregion
}
Ответ 3
Похоже, что мой компьютер просматривает файл autorun.inf и использует значение label = из раздела [autorun].
Все еще не совсем уверен, откуда появляются метки "DVD RW Drive" и "Floppy Disk Drive", но я думаю, они могут быть жестко закодированы на основе типа диска.
Ответ 4
Я надеюсь, что следующее вам поможет:
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
static extern bool GetVolumeInformation(string Volume,
StringBuilder VolumeName, uint VolumeNameSize,
out uint SerialNumber, out uint SerialNumberLength, out uint flags,
StringBuilder fs, uint fs_size);
private void Form1_Load(object sender, EventArgs e)
{
uint serialNum, serialNumLength, flags;
StringBuilder volumename = new StringBuilder(256);
StringBuilder fstype = new StringBuilder(256);
bool ok = false;
Cursor.Current = Cursors.WaitCursor;
foreach (string drives in Environment.GetLogicalDrives())
{
ok = GetVolumeInformation(drives, volumename, (uint)volumename.Capacity - 1, out serialNum,
out serialNumLength, out flags, fstype, (uint)fstype.Capacity - 1);
if (ok)
{
lblVolume.Text = lblVolume.Text + "\n Volume Information of " + drives + "\n";
lblVolume.Text = lblVolume.Text + "\nSerialNumber of is..... " + serialNum.ToString() + " \n";
if (volumename != null)
{
lblVolume.Text = lblVolume.Text + "VolumeName is..... " + volumename.ToString() + " \n";
}
if (fstype != null)
{
lblVolume.Text = lblVolume.Text + "FileType is..... " + fstype.ToString() + " \n";
}
}
ok = false;
}
Cursor.Current = Cursors.Default;
}
Ответ 5
Я не пробовал этот сам, но в реестре искать
HKLM/Software/Microsoft/Windows/CurrentVersion/Explorer/DriveIcons/[Drive-Letter]/
затем прочитайте
DefaultLabel
ключ. Также ПРЕДУПРЕЖДЕНИЕ! запись недопустимых ключей/значений в реестр может серьезно повредить вашу систему! Убедитесь, что вы уверены, что делаете, прежде чем продолжить. Вот ресурс, который поможет вам получить доступ к реестру программно.
Ответ 6
Это похоже на то, что это может быть решение.
Ответ 7
Он находится в папке autorun.inf. Моя метка тома для моего флеш-накопителя - это просто 16G,
но, поставив файл autorun.inf со следующим текстом
[Автозапуска]
label = Мой 16-гигабайтный флеш-диск
а затем используя атрибут + s + h + r файла, он не отображается, если у меня нет
показать скрытые файлы И показать системные файлы в папке options/view enabled.
Чтобы программно найти это через С#, я, честно говоря, не пытался открыть autorun.inf,
но он должен быть прямым, проверьте, игнорирует ли File.Exists(Диск:\autorun.inf)
тот факт, что он + s + h + r (на всякий случай кто-то установил его), затем откройте его только для чтения
и проанализируйте строку label =. Если на самом деле файл присутствует, используйте метку автозапуска вместо
метка тома.
Я все еще могу использовать тег autorun.inf label =, даже в Windows 7, чтобы изменить метку.
Ответ 8
Недавно у меня была та же проблема, которую я смог решить. Вот как получить метки в том виде, в каком они отображаются в проводнике Windows:
- Добавьте
C:\Windows\System32\shell32.dll
в качестве ссылки.
- Добавить
using Shell32;
- Создайте объект оболочки:
dynamic shellObject = Activator.CreateInstance(Type.GetTypeFromProgID("Shell.Application"));
- Получить данные на диске:
var driveData = (Folder2)ShellObject.NameSpace(driveInfo.Name);
- Параметр
driveData.Name
будет содержать метку (например: "Локальный диск (C :)").
И ниже полный код:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using Shell32;
namespace VolumeLabels
{
static class Drives
{
[DebuggerDisplay("Name: '{Name,nq}', Path: '{Path,nq}'")]
public struct DriveNameInfo
{
public string Name { get; }
public string Path { get; }
public DriveNameInfo(string name, string path)
{
Name = name;
Path = path;
}
public override string ToString()
{
return Name;
}
}
private static dynamic _shellObject;
private static dynamic ShellObject => _shellObject ?? (_shellObject = Activator.CreateInstance(Type.GetTypeFromProgID("Shell.Application")));
public static IEnumerable<DriveNameInfo> Get()
{
foreach (var driveInfo in DriveInfo.GetDrives())
{
var driveData = (Folder2)ShellObject.NameSpace(driveInfo.Name);
if (driveData == null)
yield break;
var driveDataSelf = driveData.Self;
yield return new DriveNameInfo(driveDataSelf.Name, driveDataSelf.Path);
}
}
}
class Program
{
static void Main(string[] args)
{
foreach (var driveNameInfo in Drives.Get())
Console.WriteLine(driveNameInfo);
Console.ReadKey(true);
}
}
}