IoSetCompletionRoutine function (wdm.h)
The IoSetCompletionRoutine routine registers an IoCompletion routine, which will be called when the next-lower-level driver has completed the requested operation for the given IRP.
Syntax
void IoSetCompletionRoutine(
[in] PIRP Irp,
[in, optional] PIO_COMPLETION_ROUTINE CompletionRoutine,
[in, optional] __drv_aliasesMem PVOID Context,
[in] BOOLEAN InvokeOnSuccess,
[in] BOOLEAN InvokeOnError,
[in] BOOLEAN InvokeOnCancel
);
Parameters
[in] Irp
Pointer to the IRP that the driver is processing.
[in, optional] CompletionRoutine
Specifies the entry point for the driver-supplied IoCompletion routine, which is called when the next-lower driver completes the packet.
[in, optional] Context
Pointer to a driver-determined context to pass to the IoCompletion routine. Context information must be stored in nonpaged memory, because the IoCompletion routine is called at IRQL <= DISPATCH_LEVEL.
[in] InvokeOnSuccess
Specifies whether the completion routine is called if the IRP is completed with a success status value in the IRP's IO_STATUS_BLOCK structure, based on results of the NT_SUCCESS macro (see Using NTSTATUS values).
[in] InvokeOnError
Specifies whether the completion routine is called if the IRP is completed with a nonsuccess status value in the IRP's IO_STATUS_BLOCK structure.
[in] InvokeOnCancel
Specifies whether the completion routine is called if a driver or the kernel has called IoCancelIrp to cancel the IRP.
Return value
None
Remarks
Only a driver that can guarantee it will not be unloaded before its completion routine finishes can use IoSetCompletionRoutine. Otherwise, the driver must use IoSetCompletionRoutineEx, which prevents the driver from unloading until its completion routine executes.
This routine sets the transfer address of the IoCompletion routine in the given IRP. The lowest-level driver in a chain of layered drivers cannot call this routine.
IoSetCompletionRoutine registers the specified routine to be called when the next-lower-level driver has completed the requested operation in any or all of the following ways:
With a success status value
With a nonsuccess status value
By canceling the IRP
Usually, the I/O status block is set by the underlying device driver. It is read but not altered by any higher-level drivers' IoCompletion routines.
Higher-level drivers that allocate IRP's with IoAllocateIrp or IoBuildAsynchronousFsdRequest must call this routine with all InvokeOnXxx parameters set to TRUE before passing the driver-allocated IRP to IoCallDriver. When the IoCompletion routine is called with such an IRP, it must free the driver-allocated IRP and any other resources that the driver set up for the request, such as MDLs with IoBuildPartialMdl. Such a driver should return STATUS_MORE_PROCESSING_REQUIRED when it calls IoFreeIrp to forestall the I/O manager's completion processing for the driver-allocated IRP.
Non-PnP drivers that might be unloaded before their IoCompletion routines run should use IoSetCompletionRoutineEx instead.