Как извлечь USB-съемный диск/том, аналогичный функции "Извлечь" в проводнике Windows?

Знаете ли вы, что такое API, или последовательность вызовов API, которые использует Windows для выполнения функции "Извлечь" , которая доступна в контекстном меню оболочки для съемных томов?

До сих пор я пробовал две вещи:

  • используя CM_Request_Device_Eject, я перечисляю съемные диски (используя API SetupDiXXX), найдите тот, который мне интересен, идите по иерархии диспетчера устройств (используя API CM_XXX) и, наконец, вызовите CM_Request_Device_Eject на devInst устройства, в которое я вовлечен. Это работает в том смысле, что он удаляет тома с "Мой компьютер" и делает устройство "безопасным для удаления" (готово к удалению), но оно не то же самое, что и контекстное меню оболочки "Извлечь" . То, как я это знаю, связано с тем, что устройство, которое я пытаюсь извлечь, должно делать что-то, когда оно выбрасывается, и что что-то не происходит, когда я делаю извлечения с помощью CM_Request_Device_Eject.

  • используя DeviceIoControl с помощью IOCTL_STORAGE_EJECT_MEDIA код. Последовательность событий:

    • получить дескриптор тома, который я заинтересован в использовании CreateFile, как это предложено в документации
    • попытайтесь заблокировать том с помощью FSCTL_LOCK_VOLUME
    • попытайтесь отключить его, используя FSCTL_DISMOUNT_VOLUME
    • отключить предотвращение удаления носителя с помощью IOCTL_STORAGE_MEDIA_REMOVAL
    • и, наконец, выполните IOCTL_STORAGE_EJECT_MEDIA.

    Это не работает вообще. Каждый из вызовов DeviceIoControl терпит неудачу с ERROR_IVALID_FUNCTION (0x00000001). Я не знаю, почему звонки терпят неудачу. Я проверил, что другие вызовы DeviceIoControl отлично работают для одного и того же дескриптора файла (например, IOCTL_STORAGE_GET_DEVICE_NUMBER)

Наконец, моя машина для разработки работает под управлением Windows 7 x64, и для того, чтобы заставить второй метод работать, я попытался запустить приложение с правами администратора и ничего не изменил.

ИЗМЕНИТЬ

В конце концов, я узнал, где я ошибся с подходом № 2. Оказывается, по какой-то причине я неправильно установил желаемый доступ при открытии ручки на том, используя CreateFile. Правильный режим доступа GENERIC_READ | GENERIC_WRITE, и я прошел 0. После исправления моей ошибки я смог успешно извлечь устройство с помощью DeviceIoControl - IOCTL_STORAGE_EJECT_MEDIA, а также с помощью метода # 1, используя CM_Request_Device_Eject.

И получается, что метод # 2 действительно является методом, используемым в контекстном меню оболочки "Извлечь" . Используя этот метод, устройство реагирует правильно.

Ответ 1

В конце концов, я узнал, где я ошибся с подходом № 2.

Оказывается, по какой-то причине я неправильно установил нужный доступ при открытии дескриптора тома с помощью CreateFile.

Правильный режим доступа GENERIC_READ | GENERIC_WRITE, и я прошел 0. После исправления моей ошибки я смог успешно извлечь устройство с помощью DeviceIoControl - IOCTL_STORAGE_EJECT_MEDIA, а также с помощью метода # 1, используя CM_Request_Device_Eject.

Наконец, оказывается, что метод # 2 действительно является методом, используемым контекстным меню оболочки "Извлечь". Используя этот метод, устройство реагирует правильно.

Ответ 3

Я случайно пришел сюда, выполняя поиск в "CM_Request_Device_Eject", и увидел, что он был похож на решение, которое я недавно сделал, объединив аналогичные части решения. Простите поздний ответ.

Я кратко изложил шаги, которые я сделал для этого в моем проекте в этом SO-ответе.