Регистрация процедуры IoCompletion
Чтобы зарегистрировать подпрограмму IoCompletion , подпрограмма диспетчеризации вызывает IoSetCompletionRoutine, предоставляя адрес подпрограммы IoCompletion и IRP, которые затем будут передаваться в более низкие драйверы с помощью IoCallDriver.
При вызове IoSetCompletionRoutine подпрограмма диспетчера диспетчера операций ввода-вывода определяет обстоятельства, в которых диспетчер операций ввода-вывода должен вызывать указанную подпрограмму IoCompletion . Вы можете выбрать, чтобы подпрограмма IoCompletion вызывалась, если драйвер более низкого уровня успешно завершает IRP (InvokeOnSuccess), завершает IRP со значением состояния ошибки (InvokeOnError) или отменяет IRP (InvokeOnCancel) в любом сочетании.
Цель процедуры IoCompletion — отслеживать, что драйверы более низкого уровня делали с IRP, и выполнять дополнительную обработку завершения, если это необходимо. В частности, ниже перечислены наиболее распространенные способы использования процедур IoCompletion драйвера.
Удаление IRP, выделенного драйвером с помощью IoAllocateIrp или IoBuildAsynchronousFsdRequest
Любой драйвер более высокого уровня, который выделяет IRP с помощью любой из этих подпрограмм поддержки, должен предоставлять подпрограмму IoCompletion для этого IRP. Подпрограмма IoCompletion должна вызывать IoFreeIrp , чтобы удалить выделенные драйвером irP.
Повторное использование входящего IRP для запроса на выполнение нескольких операций, таких как частичная передача драйверов, до тех пор, пока исходный запрос не будет выполнен процедурой IoCompletion .
Повторная попытка запроса, завершаемого драйвером более низкого уровня с ошибкой
Драйверы самого высокого уровня, такие как файловые системы, скорее всего, имеют подпрограммы IoCompletion , которые пытаются повторить запросы, чем промежуточные драйверы, за исключением драйверов классов, размещенных над тесно связанных драйверов портов. Однако любой промежуточный драйвер использует подпрограммы IoCompletion для повторных запросов.
В то время как подпрограмма DispatchReadWrite самого высокого или промежуточного уровня драйвера, скорее всего, обрабатывает irp, для которых требуется процедура IoCompletion , любая подпрограмма диспетчеризации в любом драйвере, который передает irP в более низкие драйверы, может зарегистрировать подпрограмму IoCompletion .
Для поставщиков irP, выделенных драйвером, и повторно используемых поставщиков интеграции подпрограмма диспетчеризации должна вызывать IoSetCompletionRoutine со следующими логическими параметрами:
Параметр InvokeOnSuccess имеет значение TRUE.
Параметр InvokeOnError имеет значение TRUE.
Параметр InvokeOnCancel имеет значение TRUE , если какой-либо более низкий драйвер в цепочке может обрабатывать отменяемые irP.
Обычно параметру InvokeOnCancel присваивается значение TRUE, независимо от того, может ли возвращаться IRP с STATUS_CANCELLED, чтобы гарантировать, что подпрограмма IoCompletion освобождает все выделенные драйвером IRP или проверяет состояние завершения каждого повторного использования IRP.
Подпрограмма диспетчеризации, которая выделяет irP для более низких драйверов с помощью IoAllocateIrp или IoBuildAsynchronousFsdRequest, должна задать подпрограмму IoCompletion для каждого выделенного драйвера IRP.
Подпрограмма диспетчеризации должна настроить состояние исходного IRP и выделенных IRP для использования подпрограммы IoCompletion . Как минимум, подпрограмме IoCompletion требуется доступ к исходному IRP и количеству выделенных дополнительных irP.
Подпрограмма диспетчеризации должна вызывать IoSetCompletionRoutine со всеми параметрами InvokeOnXxx для выделенных им параметров IRP.
Подпрограмма диспетчеризации, которая повторно использует irP для последовательности операций или выполняет повторную операцию ввода-вывода, должна вызывать IoSetCompletionRoutine для каждого IRP, который будет использоваться повторно или повторно использоваться.
Подпрограмма диспетчеризации должна сохранять сведения о состоянии исходного IRP для последующего использования подпрограммой IoCompletion .
Например, подпрограмма DispatchReadWrite должна сохранить соответствующие параметры передачи входного IRP для процедуры IoCompletion перед настройкой частичной передачи для следующего ниже драйвера в этом IRP. Сохранение параметров особенно важно, если подпрограмма DispatchReadWrite изменяет любые параметры, необходимые подпрограмме IoCompletion , чтобы определить, когда был выполнен исходный запрос.
Если подпрограмма IoCompletion может повторить запрос, подпрограмма диспетчеризации должна настроить верхний предел, определенный драйвером, для количества повторных попыток, которые должна предпринять ее подпрограмма IoCompletion , прежде чем завершит исходный IRP с ошибкой.
При повторном использовании IRP подпрограмма диспетчеризации должна вызывать IoSetCompletionRoutine со всеми параметрами InvokeOnXxx, равными TRUE.
Для асинхронного запроса подпрограмма диспетчеризации любого промежуточного драйвера должна вызывать IoMarkIrpPending для исходного IRP. Затем он должен вернуть STATUS_PENDING после отправки IRP в более низкие драйверы.