Поделиться через


Обработка запроса IRP_MN_QUERY_REMOVE_DEVICE

Диспетчер PnP отправляет этот IRP, чтобы сообщить драйверам о том, что устройство вскоре будет удалено с компьютера, и попросить, можно ли удалить устройство, не нарушая работу компьютера. Он также отправляет этот IRP, когда пользователь запрашивает обновление драйверов для устройства.

Диспетчер PnP отправляет этот IRP на уровне IRQL PASSIVE_LEVEL в контексте системного потока.

Прежде чем отправить этот IRP драйверам для устройства, оно выполняет следующее:

  • Уведомляет все приложения в пользовательском режиме, зарегистрированные для уведомления на устройстве (или связанное устройство).

    К ним относятся приложения, зарегистрированные для уведомления на устройстве, на одном из потомков устройства (дочернее устройство, дочерний ребенок и т. д.) или на одном из связи удаленияустройства. Приложение регистрирует такое уведомление путем вызова CM_Register_Notification или RegisterDeviceNotification.

    В ответ на это уведомление приложение либо готовится к удалению устройства (закрывает дескрипторы устройства), либо отвечает отказом на запрос. Дополнительную информацию о том, как обрабатывать эти уведомления, см. в регистрации уведомлений о подключении интерфейса устройства и удалении устройств.

  • Уведомляет все драйверы в режиме ядра, зарегистрированные для получения уведомлений на устройстве (или связанном устройстве).

    Сюда входят драйверы, зарегистрированные для уведомления на устройстве, на одном из потомков устройства или на одном из связи удаленияустройства. Драйвер регистрирует это уведомление путем вызова IoRegisterPlugPlayNotification с категорией событий EventCategoryTargetDeviceChange.

    В ответ на это уведомление водитель либо готовится к удалению устройства (закрывает дескрипторы устройства), либо отклоняет запрос.

  • Отправляет IRP_MN_QUERY_REMOVE_DEVICE IRP драйверам потомков устройства. Дополнительные сведения о том, как стек устройств обрабатывает этот IRP, см. ниже.

  • (Системы Windows 2000 и более поздних версий) Если файловая система подключена на устройстве, диспетчер PnP отправляет запрос на удаление запроса в файловую систему и все фильтры файловой системы. Если на устройстве открытые дескрипторы, файловая система обычно отклоняет запрос на удаление устройства. Если нет, файловая система обычно блокирует том, чтобы предотвратить успешное выполнение будущих операций создания. Если подключенная файловая система не поддерживает запрос на отключение, диспетчер PnP отклоняет запрос на отключение для устройства.

Если все описанные выше действия выполнены, диспетчер PnP отправляет IRP_MN_QUERY_REMOVE_DEVICE драйверам для устройства.

Запрос IRP_MN_QUERY_REMOVE_DEVICE сначала обрабатывается верхним драйвером в стеке устройств, а затем каждым следующим более низким драйвером. Драйвер обрабатывает удаленные IRP в процедуре DispatchPnP.

В ответ на IRP_MN_QUERY_REMOVE_DEVICEдрайвер должен выполнить следующее:

  1. Определите, можно ли безопасно удалить устройство с компьютера.

    Драйвер должен отклонить IRP запроса на удаление, если одно из следующих условий истинно:

    • При удалении устройства может привести к потере данных.

    • Если компонент имеет открытый дескриптор для устройства. (Это проблема только в Windows 98/Me. Windows 2000 и более поздние версии Windows отслеживают открытые дескрипторы и завершают запрос, если после завершения IRP_MN_QUERY_REMOVE_DEVICE остаются открытые дескрипторы.)

    • Если драйвер был уведомлен (через IRP_MN_DEVICE_USAGE_NOTIFICATION IRP), что устройство расположено на пути к файлу подкачки, аварийному дампу или файлу гибернации.

    • Если драйвер имеет выдающуюся ссылку на интерфейс для устройства. То есть драйвер предоставил интерфейс в ответ на запрос IRP_MN_QUERY_INTERFACE, и интерфейс не был декрементирован.

  2. Если устройство не удается удалить, отклоните запрос на удаление IRP.

    Задайте Irp->IoStatus.Status в соответствующее состояние ошибки (обычно STATUS_UNSUCCESSFUL), вызовите IoCompleteRequest с параметром IO_NO_INCREMENT и вернитесь из подпрограммы DispatchPnP драйвера. Не передайте IRP следующему нижнему драйверу.

  3. Если драйвер ранее отправил запрос IRP_MN_WAIT_WAKE, чтобы включить устройство для пробуждения, отмените IRP ожидания-пробуждения.

  4. Запишите предыдущее состояние PnP устройства.

    Драйвер должен записать состояние PnP, в которое устройство находилось, когда драйвер получил запрос IRP_MN_QUERY_REMOVE_DEVICE, так как драйвер должен вернуть устройство в это состояние, если запрос отменен (IRP_MN_CANCEL_REMOVE_DEVICE). Предыдущее состояние обычно "запущено", которое является состоянием, которое устройство вводит, когда драйвер успешно завершает запрос IRP_MN_START_DEVICE.

    Однако возможны другие предыдущие состояния. Например, пользователь может отключить устройство с помощью диспетчера устройств. Или, в ответ на запрос IRP_MN_QUERY_CAPABILITIES, драйвер родительской шины (или драйвер фильтра для драйвера шины) мог сообщить, что оборудование устройства отключено. В любом случае драйвер для отключенного устройства может получить запрос IRP_MN_QUERY_REMOVE_DEVICE до получения запроса IRP_MN_START_DEVICE.

  5. Завершите IRP:

    В функции или драйвере фильтра:

    • Задайте значение Irp->IoStatus.Status на STATUS_SUCCESS.

    • Настройте следующее расположение стека с помощью IoSkipCurrentIrpStackLocation и передайте IRP следующему нижнему драйверу с помощью IoCallDriver.

    • Распространите статус из IoCallDriver как статус возврата из подпрограммы DispatchPnP.

    • Не завершайте IRP.

    В автобусе водитель:

    • Задайте Irp->IoStatus.Status значение STATUS_SUCCESS.

    • Завершите IRP (IoCompleteRequest) с IO_NO_INCREMENT.

    • Вернитесь из подпрограммы DispatchPnP.

Если любой драйвер в стеке устройств выдает ошибку IRP_MN_QUERY_REMOVE_DEVICE, диспетчер PnP отправляет IRP_MN_CANCEL_REMOVE_DEVICE в стек устройств. Это предотвращает необходимость выполнения IoCompletion подпрограммы для запроса на удаление IRP водителями, чтобы определить, потерпел ли сбой IRP более низкий драйвер.

После того как драйвер успешно выполнит IRP_MN_QUERY_REMOVE_DEVICE и определит, что устройство находится в состоянии ожидания удаления, он должен отклонить все последующие запросы на создание устройства. Драйвер обрабатывает все остальные IRPs как обычно, пока драйвер не получит IRP_MN_CANCEL_REMOVE_DEVICE или IRP_MN_REMOVE_DEVICE.