Completing I/O Requests
Every framework-based driver must eventually complete every I/O request that it receives from the framework. Drivers complete requests by calling the request object's WdfRequestComplete, WdfRequestCompleteWithInformation, or WdfRequestCompleteWithPriorityBoost method.
A driver must complete a request when it determines that one of the following cases is true:
The requested I/O operation has finished successfully.
The requested I/O operation was started but failed before it finished.
The requested I/O operation is not supported, or was not valid at the time it was received, and could not be started.
The requested I/O operation was canceled.
If your driver forwards the I/O request synchronously to the I/O target, the driver's call to the I/O target returns only after a lower-level driver has completed the request (unless an error occurs). After the I/O target returns, your driver must call WdfRequestComplete.
If your driver forwards the I/O request asynchronously, you will want your driver to be notified when a lower-level driver completes the request. If your driver registers a CompletionRoutine callback function, the framework calls this callback function after the I/O target completes the request. The CompletionRoutine callback function typically calls WdfRequestComplete.
If your driver does not need to be notified when an I/O target completes an asynchronously forwarded I/O request, the driver does not have to register a CompletionRoutine callback function. Instead, the driver can set the WDF_REQUEST_SEND_OPTION_SEND_AND_FORGET flag when calling WdfRequestSend. In this case the driver does not call WdfRequestComplete.
A driver does not complete an I/O request that it has created by calling WdfRequestCreate or WdfRequestCreateFromIrp. Instead, the driver must call WdfObjectDelete to delete the request object, typically after an I/O target has completed the request.
For example, a driver might receive a read or write request for an amount of data that is larger than the driver's I/O targets can handle at one time. The driver must divide the data into several smaller requests and send these smaller requests to one or more I/O targets. Techniques for handling this situation include:
Calling WdfRequestCreate to create a single additional request object that represents a smaller request.
The driver can send this request synchronously to an I/O target. The smaller request's CompletionRoutine callback function can call WdfRequestReuse so that the driver can reuse the request and send it to the I/O target again. After the I/O target completes the last of the smaller requests, the CompletionRoutine callback function can call WdfObjectDelete to delete the driver-created request object and the driver can call WdfRequestComplete to complete the original request.
Calling WdfRequestCreate to create several additional request objects that represent the smaller requests.
The driver's I/O targets can process these multiple smaller requests asynchronously. The driver can register a CompletionRoutine callback function for each of the smaller requests. Each time that the CompletionRoutine callback function is called, it can call WdfObjectDelete to delete a driver-created request object. After the I/O target completes all of the smaller requests, the driver can call WdfRequestComplete to complete the original request.
When a driver completes a request, it can optionally provide some additional information that other drivers can access. For example, a driver might provide the number of bytes that were transferred for a read or write request. To provide this information, the driver can do either of the following:
To obtain information about an I/O request that another driver has completed, a driver can:
Call WdfRequestGetCompletionParams to obtain a WDF_REQUEST_COMPLETION_PARAMS structure that contains additional information about the completed request, such as handles to memory objects that represent the request's buffers, or bus-specific information.
A driver can call WdfRequestGetCompletionParams only after it calls WdfRequestSend to send the I/O request synchronously or asynchronously to an I/O target. The driver must not call WdfRequestGetCompletionParams after it calls one of the methods that send I/O requests to I/O targets only synchronously (such as WdfIoTargetSendReadSynchronously).
Call WdfRequestGetInformation to obtain additional I/O completion information that the lower-level driver specified when it called WdfRequestSetInformation or WdfRequestCompleteWithInformation, if drivers in the driver stack provide such information.
If a driver sends an I/O request synchronously, it typically calls WdfRequestGetStatus, WdfRequestGetCompletionParams, and WdfRequestGetInformation after the synchronous call returns. If a driver sends an I/O request asynchronously, it typically calls these methods from within a CompletionRoutine callback function.
For more information about completing I/O requests, see Synchronizing Cancel and Completion Code.