Программное извлечение USB накопителей

      Рассмотрим пример программы для извлечения USB накопителей с использованием WinAPI. Для извлечения накопителя будем использовать библиотеку «kernel32» и три ее функции. Функция DeviceIoControl отправляет управляющий код непосредственно указанному драйверу устройства, заставляя соответствующее устройство выполнить соответствующую операцию. Чтобы извлечь устройство, необходимы данные о дескрипторе устройства. DeviceIoControl может принять дескриптор конкретного устройства. Например, чтобы открыть дескриптор логического диска A: при помощи функции CreateFile, необходимо задать \\.\a:. Альтернативно, вы можете использовать имена \\.\PhysicalDrive0, \\.\PhysicalDrive1 и так далее, чтобы открывать дескрипторы на физические диски в системе.
     Мы будем использовать букву устройства, которую присвоила операционная система. Для этого предварительно выполним поиск всех USB накопителей с использованием Windows Management Instrumentation (WMI), а так же для удобства выбора накопителя, будем заносить данные в компонент «СomboBox». Если операция извлечения завершается успешно, DeviceIoControl возвращает ненулевое значение, иначе возвращается ноль. После выполнения запроса на извлечение, необходимо с помощью функции CloseHandle закрыть дескриптор открытого объекта. Если функция завершается успешно, величина возвращаемого значения - не ноль.
       Создайте проект Windows Form в Microsoft Visual Studio и добавьте на главную форму два компонента:
  • ComboBox – Список доступных для извлечения USB накопителей;
  • Button – Кнопка для извлечения выбранного USB накопителя.
У вас получится представленный ниже вариант:
      Сделайте двойной клик по компоненту «button1» и перейдите в автоматически созданный метод «button1_Click». Добавьте в него приведенный ниже листинг вызова метода извлечения и обновления списка.
EjectDrive(kvp[comboBox1.SelectedIndex]);
//Обновляем список накопителей
LoadInfo();
Добавьте в листинг главной формы, приведенный ниже код извлечения USB накопителя.
const int OPEN_EXISTING = 3;
const uint GENERIC_READ = 0x80000000;
const uint GENERIC_WRITE = 0x40000000;
const uint IOCTL_STORAGE_EJECT_MEDIA = 0x2D4808;

[System.Runtime.InteropServices.DllImport("kernel32")]
private static extern int CloseHandle(IntPtr handle);

[System.Runtime.InteropServices.DllImport("kernel32")]
private static extern int DeviceIoControl
    (IntPtr deviceHandle, uint ioControlCode,
      IntPtr inBuffer, int inBufferSize,
      IntPtr outBuffer, int outBufferSize,
      ref int bytesReturned, IntPtr overlapped);

[System.Runtime.InteropServices.DllImport("kernel32")]
private static extern IntPtr CreateFile
    (string filename, uint desiredAccess,
      uint shareMode, IntPtr securityAttributes,
      int creationDisposition, int flagsAndAttributes,
      IntPtr templateFile);

List kvp;

//Получение списка букв USB накопителей
private void UsbDiskList()
{
    string diskName = string.Empty;
    kvp = new List();
    //предварительно очищаем список
    comboBox1.Items.Clear();

    //Получение списка накопителей подключенных через интерфейс USB
    foreach (System.Management.ManagementObject drive in
              new System.Management.ManagementObjectSearcher(
               "select * from Win32_DiskDrive where InterfaceType='USB'").Get())
    {
        //Получаем букву накопителя
        foreach (System.Management.ManagementObject partition in
           new System.Management.ManagementObjectSearcher(
            "ASSOCIATORS OF {Win32_DiskDrive.DeviceID='" + drive["DeviceID"]
              + "'} WHERE AssocClass = Win32_DiskDriveToDiskPartition").Get())
        {
            foreach (System.Management.ManagementObject disk in
               new System.Management.ManagementObjectSearcher(
                "ASSOCIATORS OF {Win32_DiskPartition.DeviceID='"
                  + partition["DeviceID"]
                  + "'} WHERE AssocClass = Win32_LogicalDiskToPartition").Get())
            {
                //Получение буквы устройства
                diskName = disk["Name"].ToString().Trim();
                comboBox1.Items.Add(diskName + " (" + drive["Model"] + ")");
                kvp.Add(diskName);
            }
        }
    }
}      

//метод для извлечения USB накопителя
static void EjectDrive(string driveLetter)
{
    string path = "\\\\.\\" + driveLetter;

    IntPtr handle = CreateFile(path, GENERIC_READ | GENERIC_WRITE, 0,
        IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero);

    if ((long)handle == -1)
    {
        MessageBox.Show("Невозможно извлечь USB устройство!", 
   "Извлечение USB накопителей", MessageBoxButtons.OK, MessageBoxIcon.Error);
        return;
    }
    int dummy = 0;
    DeviceIoControl(handle, IOCTL_STORAGE_EJECT_MEDIA, IntPtr.Zero, 0,
        IntPtr.Zero, 0, ref dummy, IntPtr.Zero);
    int returnValue = DeviceIoControl(handle, IOCTL_STORAGE_EJECT_MEDIA,
             IntPtr.Zero, 0, IntPtr.Zero, 0, ref dummy, IntPtr.Zero);
    CloseHandle(handle);
    MessageBox.Show("USB устройство, успешно извлечено!",
 "Извлечение USB накопителей",MessageBoxButtons.OK,MessageBoxIcon.Information);          
}
private void LoadInfo()
{
    //Загрузка букв USB накопителей при запуске программы
    UsbDiskList();
    //Выбор первого устройства в списке
    comboBox1.SelectedIndex = 0;
}
      Для получения списка букв USB накопителей сразу при запуске вашей программы, добавьте в метод «Form1()» после строчки инициализации компонентов, вызов метода «LoadInfo();». Запустите проект, нажав на клавиатуре, клавишу «F5». Если у вас имеются уже вставленные в компьютер USB накопители, программа сразу отобразит их в списке и автоматически выберет первое из них.
      Выберете необходимое вам для извлечения устройство и нажмите на кнопку «Извлечь». В случае если устройство не занято процессами, вы увидите соответствующее сообщение:
Или сообщение об ошибке:
Минусы данного решения:
  • Необходимо чтобы флешка не была занята процессами;
  • Не извлекает USB hard drive.

Ссылка для скачивания примера: Rusfolder.net


1 комментарий:

  1. Сообщение об извлечении появляется, но флешка все равно остается в системе.

    ОтветитьУдалить

Большая просьба, не писать в комментариях всякую ерунду не по теме!