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


Предварительная обработка и последующая обработка IRPs

[Применимо только к KMDF]

Если драйвер должен перехватывать пакет запросов ввода-вывода (IRP) до или после того, как фреймворк обрабатывает IRP, драйвер может вызывать WdfDeviceInitAssignWdmIrpPreprocessCallback для регистрации функции обратного вызова для события EvtDeviceWdmIrpPreprocess, связанного с основным кодом функции ввода-вывода и, при необходимости, с конкретными дополнительными кодами функций ввода-вывода, связанными с основным кодом. Впоследствии платформа вызывает функцию обратного вызова драйвера EvtDeviceWdmIrpPreprocess, когда драйвер получает IRP, содержащий указанный основной и дополнительный код функции.

Функция обратного вызова EvtDeviceWdmIrpPreprocess может выполнять все действия, необходимые для предварительной обработки IRP, а затем вызывать WdfDeviceWdmDispatchPreprocessedIrp, чтобы вернуть IRP в платформу, если драйвер не обрабатывает IRP, что платформа не поддерживает.

Когда драйвер вызывает WdfDeviceWdmDispatchPreprocessedIrp, фреймворк обрабатывает IRP так же, как если бы драйвер не предоставил бы функцию обратного вызова EvtDeviceWdmIrpPreprocess. Если код функции ввода-вывода IRP — это код, который платформа передает драйверам, драйвер снова получит IRP в качестве объекта запроса.

Если драйверу необходимо обработать IRP после того, как драйвер более низкого уровня завершит его, функция обратного вызова EvtDeviceWdmIrpPreprocess может вызвать IoSetCompletionRoutine, чтобы задать рутинный IoCompletion перед вызовом WdfDeviceWdmDispatchPreprocessedIrp.

После вызова драйвера WdfDeviceInitAssignWdmIrpPreprocessCallback, фреймворк вызывает менеджер ввода-вывода, чтобы добавить дополнительное расположение стека ввода-вывода ко всем IRP, так что функция обратного вызова EvtDeviceWdmIrpPreprocess может установить рутин IoCompletion. Функция обратного вызова должна обновить указатель места в стеке ввода-вывода IRP перед вызовом WdfDeviceWdmDispatchPreprocessedIrp.

Вызов WdfDeviceWdmDispatchPreprocessedIrp

Так как диспетчер ввода-вывода добавляет дополнительное расположение стека ввода-вывода в IRP, Функция обратного вызова EvtDeviceWdmIrpPreprocess должна вызывать IoSkipCurrentIrpStackLocation или IoCopyCurrentIrpStackLocationToNext (чтобы настроить следующее расположение стека ввода-вывода в IRP) перед вызовом WdfDeviceWdmDispatchPreprocessedIrp.

Если драйвер предварительно обрабатывает IRP, но не обрабатывает IRP после предварительной обработки, нет необходимости задавать процедуру IoCompletion для IRP, и можно вызывать IoSkipCurrentIrpStackLocation, как показано в следующем примере кода.

NTSTATUS
  EvtDeviceMyIrpPreprocess(
    IN WDFDEVICE Device,
    IN OUT PIRP Irp
    )
{
//
// Perform IRP preprocessing operations here.
//
...
//
// Deliver the IRP back to the framework. 
//
IoSkipCurrentIrpStackLocation(Irp);
return WdfDeviceWdmDispatchPreprocessedIrp(Device, Irp);
}

Если драйвер выполняет постобработку IRP, драйвер должен вызвать IoCopyCurrentIrpStackLocationToNext, а затем вызвать IoSetCompletionRoutine, чтобы задать подпрограмму IoCompletion для IRP, как показано в следующем примере кода.

NTSTATUS
  EvtDeviceMyIrpPreprocess(
    IN WDFDEVICE Device,
    IN OUT PIRP Irp
    )
{
//
// Perform IRP preprocessing operations here, if needed.
//
...
//
// Set a completion routine and deliver the IRP back to
// the framework. 
//
IoCopyCurrentIrpStackLocationToNext(Irp);
IoSetCompletionRoutine(
                       Irp,
                       MyIrpCompletionRoutine,
                       NULL,
                       TRUE,
                       TRUE,
                       TRUE
                      );
return WdfDeviceWdmDispatchPreprocessedIrp(Device, Irp);
}

Драйвер не должен вызывать IoCopyCurrentIrpStackLocationToNext (и, следовательно, не должен устанавливать подпрограмму завершения IoCompletion), если объект устройства, который получает функция обратного вызова EvtDeviceWdmIrpPreprocess, представляет собой объект физического устройства (PDO), а основной код функции IRP — это IRP_MJ_PNP или IRP_MJ_POWER. В противном случае средство проверки драйвера сообщит об ошибке.

Дополнительные сведения о том, когда следует вызывать IoCopyCurrentIrpStackLocationToNext, IoSkipCurrentIrpStackLocationи IoSetCompletionRoutine, см. передачу IRPs вниз по стеку драйверов.