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


функция обратного вызова 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 (см. раздел "Примечания").