Preprocessing and Postprocessing IRPs

[Applies to KMDF only]

If your driver must intercept an I/O request packet (IRP) before or after the framework handles the IRP, the driver can call WdfDeviceInitAssignWdmIrpPreprocessCallback to register an EvtDeviceWdmIrpPreprocess event callback function for a major I/O function code and, optionally, for specific minor I/O function codes that are associated with the major code. Subsequently, the framework calls the driver's EvtDeviceWdmIrpPreprocess callback function whenever the driver receives an IRP that contains a specified major and minor function code.

The EvtDeviceWdmIrpPreprocess callback function can do whatever is necessary to preprocess the IRP, and then it must call WdfDeviceWdmDispatchPreprocessedIrp to return the IRP to the framework unless the driver is handling an IRP that the framework does not support.

After the driver calls WdfDeviceWdmDispatchPreprocessedIrp, the framework processes the IRP in the same way that it would have if the driver had not provided an EvtDeviceWdmIrpPreprocess callback function. If the IRP's I/O function code is one that the framework passes to drivers, the driver will receive the IRP again as a request object.

If the driver needs to postprocess the IRP after a lower-level driver completes the IRP, the driver's EvtDeviceWdmIrpPreprocess callback function can call IoSetCompletionRoutine to set an IoCompletion routine before it calls WdfDeviceWdmDispatchPreprocessedIrp.

After your driver calls WdfDeviceInitAssignWdmIrpPreprocessCallback, the framework causes the I/O manager to add an additional I/O stack location to all IRPs so that the EvtDeviceWdmIrpPreprocess callback function can set an IoCompletion routine. The callback function must update the IRP's I/O stack location pointer before it calls WdfDeviceWdmDispatchPreprocessedIrp.

Calling WdfDeviceWdmDispatchPreprocessedIrp

Because the I/O manager adds an additional I/O stack location to the IRP, the EvtDeviceWdmIrpPreprocess callback function must call IoSkipCurrentIrpStackLocation or IoCopyCurrentIrpStackLocationToNext (to set up the next I/O stack location in the IRP) before calling WdfDeviceWdmDispatchPreprocessedIrp.

If your driver is preprocessing an IRP, but not postprocessing the IRP, the driver does not need to set an IoCompletion routine for the IRP and can call IoSkipCurrentIrpStackLocation, as the following code example shows.

NTSTATUS
  EvtDeviceMyIrpPreprocess(
    IN WDFDEVICE Device,
    IN OUT PIRP Irp
    )
{
//
// Perform IRP preprocessing operations here.
//
...
//
// Deliver the IRP back to the framework. 
//
IoSkipCurrentIrpStackLocation(Irp);
return WdfDeviceWdmDispatchPreprocessedIrp(Device, Irp);
}

If your driver is postprocessing the IRP, the driver must call IoCopyCurrentIrpStackLocationToNext, and then it must call IoSetCompletionRoutine to set an IoCompletion routine for the IRP, as the following code example shows.

NTSTATUS
  EvtDeviceMyIrpPreprocess(
    IN WDFDEVICE Device,
    IN OUT PIRP Irp
    )
{
//
// Perform IRP preprocessing operations here, if needed.
//
...
//
// Set a completion routine and deliver the IRP back to
// the framework. 
//
IoCopyCurrentIrpStackLocationToNext(Irp);
IoSetCompletionRoutine(
                       Irp,
                       MyIrpCompletionRoutine,
                       NULL,
                       TRUE,
                       TRUE,
                       TRUE
                      );
return WdfDeviceWdmDispatchPreprocessedIrp(Device, Irp);
}

Your driver must not call IoCopyCurrentIrpStackLocationToNext (and therefore must not set an IoCompletion routine) if the device object handle that the driver's EvtDeviceWdmIrpPreprocess callback function receives represents a physical device object (PDO), and if the IRP's major function code is IRP_MJ_PNP or IRP_MJ_POWER. Otherwise, Driver Verifier will report an error.

For more information about when to call IoCopyCurrentIrpStackLocationToNext, IoSkipCurrentIrpStackLocation, and IoSetCompletionRoutine, see Passing IRPs down the Driver Stack.