Самоучитель по программированию систем защиты

       

Получение драйвером вышележащего



Получение драйвером вышележащего уровня уведомления о завершении обработки IRP драйвером нижележащего уровня

В некоторых случаях драйвер вышележащего уровня может захотеть получить уведомление о завершении обработки переданного им запроса ввода/вывода драйвером нижележащего уровня(CompletionNotification). Это может быть сделано с помощью вызова функции IoSetCompletionRoutine() перед передачей пакета IRP драйверу нижележащего уровня любым указанным выше способом.

VOID loSetCompletionRoutine(IN PIRP Irp,

IN PIO_COMPLETION_ROUTINE CompletionRoutine,

INPVOID Context,

IN BOOLEAN InvokeOnSuccess,

IN BOOLEAN InvokeOnError,

IN BOOLEAN InvokeOnCahcel);

Где: Irp - Указатель на IRP, при завершении которого вызывается точка входа CompletionRoutine;

CompletionRoutine - Указатель на точку входа драйвера, вызываемую при завершении IRP;

Context - определенное драйвером значение, которое нужно передать как третий параметр для точки входа CompletionRoutine;

InvokeOnSuccess, InvokeOnError, IwokeOnCancel - Параметры, которые, указывают должна ли точка входа CompletionRoutine быть вызвана при завершении IRP с указанным состоянием.

В качестве второго параметра в вызове loSetCompletionRoutine() передается адрес точки входа драйвера, которая должна быть вызвана при завершении указанного в первом параметре пакета IRP. Прототип функции - точки входа драйвера:



NTSTATUS CompletionRoutine(IN PDEVICE_OBJECT DeviceObject,

IN PIRP Irp,

IN PVOID Context) ;

Где: DeviceObject — Указатель на объект-устройство, которому предназначался закончившийся пакетIRP;

IRP - Указатель на закончившийся пакет IRP;

Context - Определенное драйвером значение контекста, переданное, когда была вызвана функция IoSetCompletionRoutine().

При вызове IoSetCompletionRoutine() указатель на функцию завершения сохраняется вIRP в следующем после текущего Стеке Размещения ввода/вывода (то есть в

Стеке Размещения ввода/вывода нижележащего драйвера). Из этого следуют два важных вывода:

  • Если драйвер установит функцию завершения для некоторого IRP и завершит этот IRP, функция завершения не будет вызвана.
  • Драйвер низшего уровня (либо монолитный драйвер) не может устанавливать функции завершения, так как, во-первых, это бессмысленно (см. предыдущий вывод), а во-вторых, это ошибка, так как следующего (за текущим) стека размещения ввода/вывода для таких драйверов не существует.
  • Функция завершения вызывается при том же уровне IRQL, при котором нижележащим драйвером была вызвана функция завершения обработки IRP - loComplete Request(). Это может быть любой уровень IRQL меньший либо равный IRQL_ DISPATCH_LEVEL.

    Если драйвер вышележащего уровня создавал новые пакеты IRP для передачи драйверу нижележащего уровня, он обязан использовать функцию завершения для этих IRP, причем параметры InvokeOnSuccess, InvokeOnError, IwokeOnCancel должны быть установлены в TRUE. В этих случаях функция завершения должна освободить созданные драйвером IRP с помощью функции IoFreeIrp() и завершить первоначальный пакет IRP.

    Требования к реализации функции завершения достаточно сложные. Эти требования можно найти в [Developing Windows NT Device Drivers, pages 481-485].

     



    Содержание раздела