функция обратного вызова IO_COMPLETION_ROUTINE (wdm.h)

Подпрограмма IoCompletion завершает обработку операций ввода-вывода.

Синтаксис

IO_COMPLETION_ROUTINE IoCompletionRoutine;

NTSTATUS IoCompletionRoutine(
  [in]           PDEVICE_OBJECT DeviceObject,
  [in]           PIRP Irp,
  [in, optional] PVOID Context
)
{...}

Параметры

[in] DeviceObject

Указатель на структуру DEVICE_OBJECT , предоставленный вызывающим. Это объект устройства для целевого устройства, ранее созданный подпрограммой AddDevice драйвера.

[in] Irp

Предоставленный вызывающим элементом указатель на структуру IRP , описывающую операцию ввода-вывода.

[in, optional] Context

Предоставленный вызывающим объектом указатель на сведения о контексте для конкретного драйвера, которые ранее предоставлялись при вызове IoSetCompletionRoutine или IoSetCompletionRoutineEx. Сведения о контексте должны храниться в непагрегированной памяти, так как подпрограмму IoCompletion можно вызвать по DISPATCH_LEVEL. Дополнительные сведения см. в разделе "Примечания".

Возвращаемое значение

Если подпрограмма IoCompletion определяет, что для IRP требуется дополнительная обработка, она должна возвращать STATUS_MORE_PROCESSING_REQUIRED. Дополнительные сведения см. в разделе "Примечания". В противном случае он должен вернуть STATUS_SUCCESS. (Диспетчер ввода-вывода проверяет только наличие или отсутствие STATUS_MORE_PROCESSING_REQUIRED.)

Комментарии

Подпрограмма IoCompletion драйвера выполняется в произвольном потоке или контексте DPC и в irQL, который меньше или равен DISPATCH_LEVEL. Так как код, написанный для выполнения на DISPATCH_LEVEL, также будет выполняться на более низких уровнях, процедуры IoCompletion должны быть разработаны для выполнения в DISPATCH_LEVEL. Однако, так как эти подпрограммы не гарантированно будут выполняться в DISPATCH_LEVEL, они не должны вызывать системные подпрограммы, которые фактически требуют выполнения в DISPATCH_LEVEL. (Дополнительные сведения о списках IRQL см. в разделе Управление приоритетами оборудования.)

Чтобы зарегистрировать подпрограмму IoCompletion для определенного IRP, драйвер должен вызвать IoSetCompletionRoutine или IoSetCompletionRoutineEx, который хранит адрес подпрограммы IoCompletion в расположении стека ввода-вывода следующего ниже драйвера. (Таким образом, драйвер самого низкого уровня не может зарегистрировать подпрограмму IoCompletion .) Драйвер обычно вызывает IoSetCompletionRoutine или IoSetCompletionRoutineEx из одной из своих подпрограмм диспетчеризации каждый раз при получении IRP. Большинство драйверов, включая все драйверы PnP, могут использовать IoSetCompletionRoutine для регистрации процедуры IoCompletion . Драйверы, отличные от PnP, которые могут быть выгружены перед выполнением их подпрограммы IoCompletion , должны использовать IoSetCompletionRoutineEx .

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

При создании IRP выделите расположение стека для текущего драйвера, а также для всех более низких драйверов. Если вы не выделяете достаточное количество расположений стека, при вызове процедуры завершения для указателя DeviceObject может быть задано значение NULL . Вы можете избежать выделения дополнительного расположения стека для текущего драйвера, если вы используете поле Контекст для передачи данных в IoCompletion , а не используете параметр DeviceObject .

Если подпрограмма IoCompletion возвращает STATUS_MORE_PROCESSING_REQUIRED, немедленно возвращается вызов нижнего драйвера IoCompleteRequest . В этом случае драйверу более высокого уровня потребуется вызвать IoCompleteRequest для завершения IRP.

Дополнительные сведения о реализации процедур IoCompletion см. в разделе Завершение irP.

Примеры

Чтобы определить подпрограмму обратного вызова IoCompletion , необходимо сначала предоставить объявление функции, определяющее тип определяемой процедуры обратного вызова. Windows предоставляет набор типов функций обратного вызова для драйверов. Объявление функции с помощью типов функций обратного вызова помогает анализу кода для драйверов, средству проверки статических драйверов (SDV) и другим средствам проверки находить ошибки, и это требование для написания драйверов для операционной системы Windows.

Например, чтобы определить подпрограмму обратного вызова IoCompletion с именем MyIoCompletion, используйте тип IO_COMPLETION_ROUTINE, как показано в следующем примере кода:

IO_COMPLETION_ROUTINE MyIoCompletion;

Затем реализуйте процедуру обратного вызова следующим образом:

_Use_decl_annotations_
NTSTATUS
  MyIoCompletion(
    PDEVICE_OBJECT  DeviceObject,
    PIRP  Irp,
    PVOID  Context
    )
  {
      // Function body
  }

Тип функции IO_COMPLETION_ROUTINE определен в файле заголовка Wdm.h. Чтобы более точно определить ошибки при запуске средств анализа кода, не забудьте добавить заметку _Use_decl_annotations_ в определение функции. Заметка _Use_decl_annotations_ гарантирует использование заметок, которые применяются к типу функции IO_COMPLETION_ROUTINE в файле заголовка. Дополнительные сведения о требованиях к объявлениям функций см. в статье Объявление функций с помощью типов ролей функций для драйверов WDM. Сведения о _Use_decl_annotations_см. в статье Поведение функции с заметками.

Требования

Требование Значение
Целевая платформа Персональный компьютер
Верхняя часть wdm.h (включая Wdm.h, Ntddk.h, Ntifs.h)
IRQL Вызывается по адресу IRQL <= DISPATCH_LEVEL (см. раздел "Замечания").